diff --git a/src/test/regress/go_driver_test/README.txt b/src/test/regress/go_driver_test/README.txt deleted file mode 100644 index 0c5b9be84..000000000 --- a/src/test/regress/go_driver_test/README.txt +++ /dev/null @@ -1,17 +0,0 @@ -This directory is using for go driver test -such way: -make gocheck p=8000 -sj - -Install db information: -datapath : current_dir/data -inituser: current os login user -inituser password: Gauss_234 -default databse: postgres -install port: default 5432 - -support parameter: -p: install db port (default 5432) -u: go driver login user (default gauss) -w: go driver login user password (default Gauss_234) -h: go driver login IP address (default 127.0.0.1) -d: go driver login user database (default gauss) \ No newline at end of file diff --git a/src/test/regress/go_driver_test/download_godriver.sh b/src/test/regress/go_driver_test/download_godriver.sh deleted file mode 100644 index 1eca19e4e..000000000 --- a/src/test/regress/go_driver_test/download_godriver.sh +++ /dev/null @@ -1,20 +0,0 @@ -#!/bin/bash -GO_DRIVRR_DIR=$work_dir/src/gitee.com/opengauss -GO_DRIVRR_PATH=$GO_DRIVRR_DIR/openGauss-connector-go-pq -DEVELOP_BRANCH=huawei/csi/gaussdb_kernel/v1.0.2 -REPOSITORY=https://codehub-dg-y.huawei.com/OpenSourceCenter/openGauss-connector-go-pq.git - -#prepare code -if [ ! -d ${GO_DRIVRR_PATH} ]; then - git config --global http.sslVerify false - mkdir -p $GO_DRIVRR_DIR - cd $GO_DRIVRR_DIR - git clone $REPOSITORY - cd $GO_DRIVRR_PATH - git reset --hard remotes/origin/${DEVELOP_BRANCH} -else - cd $GO_DRIVRR_PATH - git remote set-url origin $REPOSITORY - git remote update origin - git reset --hard remotes/origin/${DEVELOP_BRANCH} -fi \ No newline at end of file diff --git a/src/test/regress/go_driver_test/process.sh b/src/test/regress/go_driver_test/process.sh deleted file mode 100644 index 20be53955..000000000 --- a/src/test/regress/go_driver_test/process.sh +++ /dev/null @@ -1,251 +0,0 @@ -#!/bin/bash - -export initu_p="Gauss@234" -work_dir=`dirname $0` -export work_dir=`realpath $work_dir` -echo "work_dir : " $work_dir - -echo "######## download go test code ######" -sh ${work_dir}/download_godriver.sh - -##set go test connection info -port=5432 -user=gauss -passwd=Gauss_234 -database=gauss -hostip=127.0.0.1 - -echo "######## parsing go test args begin ######" $@ -for arg in $@ -do - val=${arg#*=} - key=${arg%=*} - echo "key="$key" val="$val" vallen="${#val} - if [ x"${#val}" != x"0" ]; then - case ${key} in - i) hostip=$val - ;; - p) port=$val - ;; - w) passwd=$val - ;; - d) database=$val - ;; - u) user=$val - ;; - *) echo "not support this arg: " $arg - ;; - esac - fi -done - -echo "host ip = "$hostip -echo "port = "$port -echo "go running user = "$user -echo "go running user password = "$passwd -echo "go running user database = "$database -echo "######## parsing go test args end ######" - -path_netstat=`which netstat` -if [ -x $path_netstat ]; then - port_check=`netstat -t | awk '{print $4}' | grep $port | wc -l` - if [ ! x"$port_check" == x"0" ]; then - echo "your input port=$port is being used, please try another port." - exit 1 - else - echo "port $port is OK." - fi -fi - -echo "######## modify go config begin ######" -go_config_filtpath=$work_dir/src/github.com/GaussKernel/property.ini -rm -rf ${go_config_filtpath}.bak -cp $go_config_filtpath ${go_config_filtpath}.bak - -sed -i "s/^host=.*/host=${hostip}/g" $go_config_filtpath -sed -i "s/^port=.*/port=${port}/g" $go_config_filtpath -sed -i "s/^password=.*/password=${passwd}/g" $go_config_filtpath -sed -i "s/^dbname=.*/dbname=${database}/g" $go_config_filtpath -sed -i "s/^user=.*/user=${user}/g" $go_config_filtpath - -# echo "port=$port" >> $go_config_filtpath -# echo "password=$passwd" >> $go_config_filtpath -# echo "dbname=$database" >> $go_config_filtpath -# echo "user=$user" >> $go_config_filtpath -# echo "host=$hostip" >> $go_config_filtpath -echo "######## modify go config end ######" - -echo "######## installing gaussdb begin ######" -command_found=`echo $PATH | grep gaussdb | wc -l` -if [ x$command_found == x"0" ]; then - exp PATH=${PREFIX_HOME}/bin:$portATH -fi - -#set install db info -export datapath=$work_dir/data -export initpasswd=Gauss_234 -echo "install db path = "$datapath -export ssl_file_dir=$work_dir/src/github.com/GaussKernel/certs - -function check_res() -{ - if [ $1 -ne 0 ]; then - echo "process error. please check" - exit 1 - fi -} - -function stop_db_running() -{ - is_running=`gs_ctl status -D $database | grep "no server running" | wc -l` - if [ x"$is_running" != x"1" ]; then - gs_ctl stop -D $datapath > /dev/null 2>&1 - fi - for pid in `ps -ux | grep $datapath | grep -v grep | awk '{print $2}'` - do - kill -9 $pid - done -} - -function prepare_ssl() -{ - cp ${ssl_file_dir}/server.crt $datapath - cp ${ssl_file_dir}/server.key $datapath - cp ${ssl_file_dir}/root.crt $datapath - - chmod 0600 $datapath/server.crt - chmod 0600 $datapath/server.key - chmod 0600 $datapath/root.crt - - rm -rf ${HOME}/.postgresql - cp -r $ssl_file_dir ${HOME} - mv ${HOME}/certs ${HOME}/.postgresql - export PGSSLKEY=${HOME}/.postgresql/postgresql.key - export PGSSLCERT=${HOME}/.postgresql/postgresql.crt - export PGSSLROOTCERT=${HOME}/.postgresql/root.crt - chmod 0600 $PGSSLKEY - chmod 0600 $PGSSLCERT - chmod 0600 $PGSSLROOTCERT -} - -function modify_param(){ - gs_guc set -Z datanode -D $datapath -c "ssl = on" - gs_guc set -Z datanode -D $datapath -c "ssl_cert_file = 'server.crt'" - gs_guc set -Z datanode -D $datapath -c "ssl_key_file = 'server.key'" - gs_guc set -Z datanode -D $datapath -c "ssl_ca_file = 'root.crt'" - gs_guc set -Z datanode -D $datapath -c "logging_collector = 'on'" - gs_guc set -Z datanode -D $datapath -c "log_connections = 'on'" - gs_guc set -Z datanode -D $datapath -c "log_disconnections = 'on'" - gs_guc set -Z datanode -D $datapath -c "log_statement = 'ddl'" - gs_guc set -Z datanode -D $datapath -c "log_rotation_age = 30d" - gs_guc set -Z datanode -D $datapath -c "log_rotation_size = 100MB" - gs_guc set -Z datanode -D $datapath -c "log_duration = 'on'" - gs_guc set -Z datanode -D $datapath -c "log_lock_waits = 'on'" - gs_guc set -Z datanode -D $datapath -c "listen_addresses = '*'" -} - -function modify_hba() -{ - echo "local all all trust" >> $datapath/pg_hba.conf - echo "host all all 0.0.0.0/0 sha256" >> $datapath/pg_hba.conf - echo "hostssl all all 0.0.0.0/0 sha256" >> $datapath/pg_hba.conf -} - -stop_db_running -rm -rf $datapath -gs_initdb -D $datapath --nodename=datanode -w $initpasswd -A trust -check_res $? -echo "port=$port" >>$datapath/postgresql.conf -gs_ctl start -D $datapath -Z single_node -l logfile -check_res $? -prepare_ssl -modify_param -modify_hba -gs_ctl restart -D $datapath -Z single_node -l logfile -check_res $? -echo "######## installing gaussdb end ######" - -echo "######## create db user begin ######" -echo " -CREATE user ${user} WITH PASSWORD '${passwd}'; -CREATE database ${database} OWNER ${user}; -GRANT ALL PRIVILEGES ON database ${database} to ${user}; -" | gsql -d postgres -p ${port} - -echo " -create schema ${user}; -create table people(id int,name varchar2(200)); -insert into people values(10,20); -" | gsql -d ${database} -p ${port} -U ${user} -W ${passwd} -h ${hostip} -echo "######## create db user end (go run scipt with this user)######" - - -echo "######## running go test begin ######" - -function cal_interval_time -{ - local t=$(awk 'BEGIN{print '$2' - '$1'}') - local z=${t%.*} - printf "%.2d:%.2d:%.2d" $((z/60/60)) $((z/60%60)) $((z%60)) -} - -export GO111MODULE=on -export GONOSUMDB="*" -export GOPATH=$work_dir -export GOPROXY=http://cmc.centralrepo.rnd.huawei.com/go,http://mirrors.tools.huawei.com/goproxy - -gotest_base=$work_dir/src/github.com/GaussKernel -gotest_base_out=${gotest_base}/go_test_out -gotest_base_expect=${gotest_base}/go_test_expect -gotest_base_diff=${gotest_base}/go_test_diff - -if [ ! -d ${gotest_base_out} ];then - mkdir -p ${gotest_base_out} -fi -if [ ! -d ${gotest_base_expect} ];then - mkdir -p ${gotest_base_expect} -fi -if [ ! -d ${gotest_base_diff} ];then - mkdir -p ${gotest_base_diff} -fi - -rm -rf ${gotest_base_out}/* - -cd ${gotest_base}/go_test -declare -i go_test_files=0 -declare -i failed_counts=0 -for file in `ls` -do - if [ -f ${file} ] && [ x"${file:0-7}" == x"test.go" ]; then - ((go_test_files++)) - start_time=$(date +%s.%N) - go test ${file} -c -o ${file}.exec - if [ $? != 0 ]; then - echo "compile file ${file} error." - continue - fi - chmod +x ${file}.exec - ./${file}.exec > ${gotest_base_out}/${file}.out 2>&1 - diff -w -B -u ${gotest_base_expect}/${file}.out ${gotest_base_out}/${file}.out > ${gotest_base_diff}/${file}.diff - end_time=$(date +%s.%N) - time_cost="$(cal_interval_time ${start_time} ${end_time})" - is_fail=`cat ${gotest_base_diff}/${file}.diff | wc -l` - if [ x"$is_fail" != x"0" ]; then - ((failed_counts++)) - printf "%-40s : FAIL %s\r\n" ${file} ${time_cost} - else - printf "%-40s : SUCCESS %s\r\n" ${file} ${time_cost} - fi - fi -done -success_counts=`expr $go_test_files - $failed_counts` -echo "Execute go test $go_test_files examples, there are $success_counts success, and $failed_counts failed." -echo "######## running go test end ######" - -echo "######## stop db and clean ######" -stop_db_running -echo "######## stop db end ######" - -if [ x"$failed_counts" != x"0" ]; then -exit 1 -fi \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/Makefile b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/Makefile deleted file mode 100644 index a84e31e9c..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -.PHONY: all root-ssl server-ssl client-ssl - -# Rebuilds self-signed root/server/client certs/keys in a consistent way -all: root-ssl server-ssl client-ssl - rm -f .srl - -root-ssl: - openssl req -new -sha256 -nodes -newkey rsa:2048 \ - -config ./certs/root.cnf \ - -keyout /tmp/root.key \ - -out /tmp/root.csr - openssl x509 -req -days 3653 -sha256 \ - -in /tmp/root.csr \ - -extfile /etc/ssl/openssl.cnf -extensions v3_ca \ - -signkey /tmp/root.key \ - -out ./certs/root.crt - -server-ssl: - openssl req -new -sha256 -nodes -newkey rsa:2048 \ - -config ./certs/server.cnf \ - -keyout ./certs/server.key \ - -out /tmp/server.csr - openssl x509 -req -days 3653 -sha256 \ - -extfile ./certs/server.cnf -extensions req_ext \ - -CA ./certs/root.crt -CAkey /tmp/root.key -CAcreateserial \ - -in /tmp/server.csr \ - -out ./certs/server.crt - -client-ssl: - openssl req -new -sha256 -nodes -newkey rsa:2048 \ - -config ./certs/postgresql.cnf \ - -keyout ./certs/postgresql.key \ - -out /tmp/postgresql.csr - openssl x509 -req -days 3653 -sha256 \ - -CA ./certs/root.crt -CAkey /tmp/root.key -CAcreateserial \ - -in /tmp/postgresql.csr \ - -out ./certs/postgresql.crt diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/README b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/README deleted file mode 100644 index 24ab7b256..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/README +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains certificates and private keys for testing some -SSL-related functionality in Travis. Do NOT use these certificates for -anything other than testing. diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/bogus_root.crt b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/bogus_root.crt deleted file mode 100644 index 1239db3a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/bogus_root.crt +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDBjCCAe6gAwIBAgIQSnDYp/Naet9HOZljF5PuwDANBgkqhkiG9w0BAQsFADAr -MRIwEAYDVQQKEwlDb2Nrcm9hY2gxFTATBgNVBAMTDENvY2tyb2FjaCBDQTAeFw0x -NjAyMDcxNjQ0MzdaFw0xNzAyMDYxNjQ0MzdaMCsxEjAQBgNVBAoTCUNvY2tyb2Fj -aDEVMBMGA1UEAxMMQ29ja3JvYWNoIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxdln3/UdgP7ayA/G1kT7upjLe4ERwQjYQ25q0e1+vgsB5jhiirxJ -e0+WkhhYu/mwoSAXzvlsbZ2PWFyfdanZeD/Lh6SvIeWXVVaPcWVWL1TEcoN2jr5+ -E85MMHmbbmaT2he8s6br2tM/UZxyTQ2XRprIzApbDssyw1c0Yufcpu3C6267FLEl -IfcWrzDhnluFhthhtGXv3ToD8IuMScMC5qlKBXtKmD1B5x14ngO/ecNJ+OlEi0HU -mavK4KWgI2rDXRZ2EnCpyTZdkc3kkRnzKcg653oOjMDRZdrhfIrha+Jq38ACsUmZ -Su7Sp5jkIHOCO8Zg+l6GKVSq37dKMapD8wIDAQABoyYwJDAOBgNVHQ8BAf8EBAMC -AuQwEgYDVR0TAQH/BAgwBgEB/wIBATANBgkqhkiG9w0BAQsFAAOCAQEAwZ2Tu0Yu -rrSVdMdoPEjT1IZd+5OhM/SLzL0ddtvTithRweLHsw2lDQYlXFqr24i3UGZJQ1sp -cqSrNwswgLUQT3vWyTjmM51HEb2vMYWKmjZ+sBQYAUP1CadrN/+OTfNGnlF1+B4w -IXOzh7EvQmJJnNybLe4a/aRvj1NE2n8Z898B76SVU9WbfKKz8VwLzuIPDqkKcZda -lMy5yzthyztV9YjcWs2zVOUGZvGdAhDrvZuUq6mSmxrBEvR2LBOggmVf3tGRT+Ls -lW7c9Lrva5zLHuqmoPP07A+vuI9a0D1X44jwGDuPWJ5RnTOQ63Uez12mKNjqleHw -DnkwNanuO8dhAA== ------END CERTIFICATE----- diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/postgresql.cnf b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/postgresql.cnf deleted file mode 100644 index fa8ffc489..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/postgresql.cnf +++ /dev/null @@ -1,10 +0,0 @@ -[req] -distinguished_name = req_distinguished_name -prompt = no - -[req_distinguished_name] -C = US -ST = Nevada -L = Las Vegas -O = github.com/lib/pq -CN = pqgosslcert diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/postgresql.crt b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/postgresql.crt deleted file mode 100644 index c1815f865..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/postgresql.crt +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDPjCCAiYCCQD4nsC6zsmIqjANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJV -UzEPMA0GA1UECAwGTmV2YWRhMRIwEAYDVQQHDAlMYXMgVmVnYXMxGjAYBgNVBAoM -EWdpdGh1Yi5jb20vbGliL3BxMQ4wDAYDVQQDDAVwcSBDQTAeFw0yMTA5MDIwMTU1 -MDJaFw0zMTA5MDMwMTU1MDJaMGQxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZOZXZh -ZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgGA1UECgwRZ2l0aHViLmNvbS9saWIv -cHExFDASBgNVBAMMC3BxZ29zc2xjZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAx0ucPVUNCrVmbyithwWrmmZ1dGudBwhSyDB6af4z5Cr+S6dx2SRU -UGUw3Lv+z+tUqQ7hJj0oNddIQeYKl/Tt6JPpZsQfERP/cUGedtyt7HnCKobBL+0B -NvHnDIUiIL4LgfiZK4DWJkGmm7nTHo/7qKAw60vCMLUW98DC0Xhlk9MHYG+e9Zai -3G0vY2X6DUYcSmzBI3JakFEgMZTQg3ofUQMz8TYeK3/DYadLXkl08d18LL3Dnefx -0xRuBPNTa2tLfVnFkfFi6Z9xVB/WhG6+X4OLnO85v5xUOGTV+g154iR7FOkrrl5F -lEUBj+yaIoTRi+MyZ/oYqWwQUDYS3+Te9wIDAQABMA0GCSqGSIb3DQEBCwUAA4IB -AQCCJpwUWCx7xfXv3vH3LQcffZycyRHYPgTCbiQw3x9aBb77jUAh5O6lEj/W0nx2 -SCTEsCsRSAiFwfUb+g/AFCW84dELRWmf38eoqACebLymqnvxyZA+O87yu07XyFZR -TnmbDMzZgsyWWGwS3JoGFk+ibWY4AImYQnSJO8Pi0kZ37ngbAyJ3RtDhhEQJWw/Q -D04p3uky/ea7Gyz0QTx5o40n4gq7nEzF1OS6IHozM840J5aZrxRiXEa56fsmJHmI -IGyI07SGlWJ15r1wc8lB+8ilnAqH1QQlYzTIW0Q4NZE7n3uQg1EVuueGiGO2ex2/ -he9lDiJfOQuPuLbOxzctP9v9 ------END CERTIFICATE----- diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/postgresql.key b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/postgresql.key deleted file mode 100644 index 8380da4bc..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/postgresql.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDHS5w9VQ0KtWZv -KK2HBauaZnV0a50HCFLIMHpp/jPkKv5Lp3HZJFRQZTDcu/7P61SpDuEmPSg110hB -5gqX9O3ok+lmxB8RE/9xQZ523K3secIqhsEv7QE28ecMhSIgvguB+JkrgNYmQaab -udMej/uooDDrS8IwtRb3wMLReGWT0wdgb571lqLcbS9jZfoNRhxKbMEjclqQUSAx -lNCDeh9RAzPxNh4rf8Nhp0teSXTx3XwsvcOd5/HTFG4E81Nra0t9WcWR8WLpn3FU -H9aEbr5fg4uc7zm/nFQ4ZNX6DXniJHsU6SuuXkWURQGP7JoihNGL4zJn+hipbBBQ -NhLf5N73AgMBAAECggEAHLNY1sRO0oH5NHzpMI6yfdPPimqM/JxIP6grmOQQ2QUQ -BhkhHiJLOiC4frFcKtk7IfWQmw8noUlVkJfuYp/VOy9B55jK2IzGtqq6hWeWbH3E -Zpdtbtd021LO8VCi75Au3BLPDCLLtEq0Ea0bKEWX+lrHcLtCRf1uR1OtOrlZ94Wl -DUhm7YJC4cS1bi6Kdf03R+fw2oFi7/QdywcT4ow032jGWOly/Jl7bSHZK7xLtM/i -9HfMwmusD/iuz7mtLU7VCpnlKZm6MfS5D427ybW8MruuiZEtQJ6QtRIrHBHk93aK -Op0tjJ6tMav1UsJzgVz9+uWILE9l0AjAa4AvbfNzEQKBgQD8mma9SLQPtBb6cXuT -CQgjE4vyph8mRnm/pTz3QLIpMiLy2+aKJD/u4cduzLw1vjuH1tlb7NQ9c891jAJh -JhwDwqKAXfFicfRs/PYWngx/XtGhbbpgm1yA6XuYL1D06gzmjzXgHvZMOFcts+GF -y0JEuV7v6eYrpQJRQYCwY6xTgwKBgQDJ+bHAlgOaC94DZEXZMiUznCCjBjAstiXG -BEN7Cnfn6vgvPm/b6BkKn4VrsCmbZQKT7QJDSOhYwXCC2ZlrKiF8GEUHX4mi8347 -8B+DsuokTLNmN61QAZbb1c3XQVnr15xH8ijm7yYs4tCBmVLKBmpw1T4IZXXlVE5k -gmee+AwIfQKBgGr+P0wnclVAc4cq8CusZKzux5VEtebxbPo21CbqWUxHtzPk3rZe -elIFggK1Z3bgF7kG0NQ18QQCfLoOTqe1i6IwG8KBiA+pst1DHD0iPqroj6RvpMTs -qXbU7ovcZs8GH+a8fBZtJufL6WkrSvfvyybu2X6HNP4Bi4S9WPPdlA1fAoGAE5m/ -vkjQoKp2KS4Z+TH8mj2UjT2Uf0JN+CGByvcBG+iZnTwZ7uVfSMCiWgkGgKYU0fY2 -OgFhSvu6x3gGg3fbOAfC6yxCVyX6IibzZ/x87HjlEA5nK1R8J2lgSHt3FoQeDn1Z -qs+ajNCWG32doy1sNvb6xiXSgybjVK2zEKJRyKECgYBJTk2IABebjvInNb6tagcI -nD4d2LgBmZJZsTruHXrpO0s3XCQcFKks4JKH1CVjd34f7LkxzEOGbE7wKBBd652s -ob6gFKnbqTniTo3NRUycB6ymo4LSaBvKgeY5hYbVxrYheRLPGY+gPVYb3VMKu9N9 -76rcaFqJOz7OeywRG5bHUg== ------END PRIVATE KEY----- diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/root.cnf b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/root.cnf deleted file mode 100644 index ea6def267..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/root.cnf +++ /dev/null @@ -1,10 +0,0 @@ -[req] -distinguished_name = req_distinguished_name -prompt = no - -[req_distinguished_name] -C = US -ST = Nevada -L = Las Vegas -O = github.com/lib/pq -CN = pq CA diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/root.crt b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/root.crt deleted file mode 100644 index 390a907c3..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/root.crt +++ /dev/null @@ -1,24 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEBjCCAu6gAwIBAgIJAPizR+OD14YnMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV -BAYTAlVTMQ8wDQYDVQQIDAZOZXZhZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgG -A1UECgwRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMMBXBxIENBMB4XDTIxMDkw -MjAxNTUwMloXDTMxMDkwMzAxNTUwMlowXjELMAkGA1UEBhMCVVMxDzANBgNVBAgM -Bk5ldmFkYTESMBAGA1UEBwwJTGFzIFZlZ2FzMRowGAYDVQQKDBFnaXRodWIuY29t -L2xpYi9wcTEOMAwGA1UEAwwFcHEgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDb9d6sjdU6GdibGrXRMOHREH3MRUS8T4TFqGgPEGVDP/V5bAZlBSGP -AN0o9DTyVLcbQpBt8zMTw9KeIzIIe5NIVkSmA16lw/YckGhOM+kZIkiDuE6qt5Ia -OQCRMdXkZ8ejG/JUu+rHU8FJZL8DE+jyYherzdjkeVAQ7JfzxAwW2Dl7T/47g337 -Pwmf17AEb8ibSqmXyUN7R5NhJQs+hvaYdNagzdx91E1H+qlyBvmiNeasUQljLvZ+ -Y8wAuU79neA+d09O4PBiYwV17rSP6SZCeGE3oLZviL/0KM9Xig88oB+2FmvQ6Zxa -L7SoBlqS+5pBZwpH7eee/wCIKAnJtMAJAgMBAAGjgcYwgcMwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUfIXEczahbcM2cFrwclJF7GbdajkwgZAGA1UdIwSBiDCB -hYAUfIXEczahbcM2cFrwclJF7GbdajmhYqRgMF4xCzAJBgNVBAYTAlVTMQ8wDQYD -VQQIDAZOZXZhZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgGA1UECgwRZ2l0aHVi -LmNvbS9saWIvcHExDjAMBgNVBAMMBXBxIENBggkA+LNH44PXhicwDQYJKoZIhvcN -AQELBQADggEBABFyGgSz2mHVJqYgX1Y+7P+MfKt83cV2uYDGYvXrLG2OGiCilVul -oTBG+8omIMSHOsQZvWMpA5H0tnnlQHrKpKpUyKkSL+Wv5GL0UtBmHX7mVRiaK2l4 -q2BjRaQUitp/FH4NSdXtVrMME5T1JBBZHsQkNL3cNRzRKwY/Vj5UGEDxDS7lILUC -e01L4oaK0iKQn4beALU+TvKoAHdPvoxpPpnhkF5ss9HmdcvRktJrKZemDJZswZ7/ -+omx8ZPIYYUH5VJJYYE88S7guAt+ZaKIUlel/t6xPbo2ZySFSg9u1uB99n+jTo3L -1rAxFnN3FCX2jBqgP29xMVmisaN5k04UmyI= ------END CERTIFICATE----- diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/server.cnf b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/server.cnf deleted file mode 100644 index ba4b55703..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/server.cnf +++ /dev/null @@ -1,29 +0,0 @@ -[ req ] -default_bits = 2048 -distinguished_name = subject -req_extensions = req_ext -x509_extensions = x509_ext -string_mask = utf8only -prompt = no - -[ subject ] -C = US -ST = Nevada -L = Las Vegas -O = github.com/lib/pq - -[ x509_ext ] -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer - -basicConstraints = CA:FALSE -keyUsage = digitalSignature, keyEncipherment -subjectAltName = DNS:postgres -nsComment = "OpenSSL Generated Certificate" - -[ req_ext ] -subjectKeyIdentifier = hash -basicConstraints = CA:FALSE -keyUsage = digitalSignature, keyEncipherment -subjectAltName = DNS:postgres -nsComment = "OpenSSL Generated Certificate" diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/server.crt b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/server.crt deleted file mode 100644 index 1a0ac0d43..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/server.crt +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDqzCCApOgAwIBAgIJAPiewLrOyYipMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV -BAYTAlVTMQ8wDQYDVQQIDAZOZXZhZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgG -A1UECgwRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMMBXBxIENBMB4XDTIxMDkw -MjAxNTUwMloXDTMxMDkwMzAxNTUwMlowTjELMAkGA1UEBhMCVVMxDzANBgNVBAgM -Bk5ldmFkYTESMBAGA1UEBwwJTGFzIFZlZ2FzMRowGAYDVQQKDBFnaXRodWIuY29t -L2xpYi9wcTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKf6H4UzmANN -QiQJe92Mf3ETMYmpZKNNO9DPEHyNLIkag+XwMrBTdcCK0mLvsNCYpXuBN6703KCd -WAFOeMmj7gOsWtvjt5Xm6bRHLgegekXzcG/jDwq/wyzeDzr/YkITuIlG44Lf9lhY -FLwiHlHOWHnwrZaEh6aU//02aQkzyX5INeXl/3TZm2G2eIH6AOxOKOU27MUsyVSQ -5DE+SDKGcRP4bElueeQWvxAXNMZYb7sVSDdfHI3zr32K4k/tC8x0fZJ5XN/dvl4t -4N4MrYlmDO5XOrb/gQH1H4iu6+5EMDfZYab4fkThnNFdfFqu4/8Scv7KZ8mWqpKM -fGAjEPctQi0CAwEAAaN8MHowHQYDVR0OBBYEFENExPbmDyFB2AJUdbMvVyhlNPD5 -MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdEQQMMAqCCHBvc3RncmVzMCwG -CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkq -hkiG9w0BAQsFAAOCAQEAMRVbV8RiEsmp9HAtnVCZmRXMIbgPGrqjeSwk586s4K8v -BSqNCqxv6s5GfCRmDYiqSqeuCVDtUJS1HsTmbxVV7Ke71WMo+xHR1ICGKOa8WGCb -TGsuicG5QZXWaxeMOg4s0qpKmKko0d1aErdVsanU5dkrVS7D6729Ffnzu4lwApk6 -invAB67p8u7sojwqRq5ce0vRaG+YFylTrWomF9kauEb8gKbQ9Xc7QfX+h+UH/mq9 -Nvdj8LOHp6/82bZdnsYUOtV4lS1IA/qzeXpqBphxqfWabD1yLtkyJyImZKq8uIPp -0CG4jhObPdWcCkXD6bg3QK3mhwlC79OtFgxWmldCRQ== ------END CERTIFICATE----- diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/server.key b/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/server.key deleted file mode 100644 index 152e0f23e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/certs/server.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCn+h+FM5gDTUIk -CXvdjH9xEzGJqWSjTTvQzxB8jSyJGoPl8DKwU3XAitJi77DQmKV7gTeu9NygnVgB -TnjJo+4DrFrb47eV5um0Ry4HoHpF83Bv4w8Kv8Ms3g86/2JCE7iJRuOC3/ZYWBS8 -Ih5Rzlh58K2WhIemlP/9NmkJM8l+SDXl5f902ZthtniB+gDsTijlNuzFLMlUkOQx -PkgyhnET+GxJbnnkFr8QFzTGWG+7FUg3XxyN8699iuJP7QvMdH2SeVzf3b5eLeDe -DK2JZgzuVzq2/4EB9R+IruvuRDA32WGm+H5E4ZzRXXxaruP/EnL+ymfJlqqSjHxg -IxD3LUItAgMBAAECggEAOE2naQ9tIZYw2EFxikZApVcooJrtx6ropMnzHbx4NBB2 -K4mChAXFj184u77ZxmGT/jzGvFcI6LE0wWNbK0NOUV7hKZk/fPhkV3AQZrAMrAu4 -IVi7PwAd3JkmA8F8XuebUDA5rDGDsgL8GD9baFJA58abeLs9eMGyuF4XgOUh4bip -hgHa76O2rcDWNY5HZqqRslw75FzlYkB0PCts/UJxSswj70kTTihyOhDlrm2TnyxI -ne54UbGRrpfs9wiheSGLjDG81qZToBHQDwoAnjjZhu1VCaBISuGbgZrxyyRyqdnn -xPW+KczMv04XyvF7v6Pz+bUEppalLXGiXnH5UtWvZQKBgQDTPCdMpNE/hwlq4nAw -Kf42zIBWfbnMLVWYoeDiAOhtl9XAUAXn76xe6Rvo0qeAo67yejdbJfRq3HvGyw+q -4PS8r9gXYmLYIPQxSoLL5+rFoBCN3qFippfjLB1j32mp7+15KjRj8FF2r6xIN8fu -XatSRsaqmvCWYLDRv/rbHnxwkwKBgQDLkyfFLF7BtwtPWKdqrwOM7ip1UKh+oDBS -vkCQ08aEFRBU7T3jChsx5GbaW6zmsSBwBwcrHclpSkz7n3aq19DDWObJR2p80Fma -rsXeIcvtEpkvT3pVX268P5d+XGs1kxgFunqTysG9yChW+xzcs5MdKBzuMPPn7rL8 -MKAzdar6PwKBgEypkzW8x3h/4Moa3k6MnwdyVs2NGaZheaRIc95yJ+jGZzxBjrMr -h+p2PbvU4BfO0AqOkpKRBtDVrlJqlggVVp04UHvEKE16QEW3Xhr0037f5cInX3j3 -Lz6yXwRFLAsR2aTUzWjL6jTh8uvO2s/GzQuyRh3a16Ar/WBShY+K0+zjAoGATnLT -xZjWnyHRmu8X/PWakamJ9RFzDPDgDlLAgM8LVgTj+UY/LgnL9wsEU6s2UuP5ExKy -QXxGDGwUhHar/SQTj+Pnc7Mwpw6HKSOmnnY5po8fNusSwml3O9XppEkrC0c236Y/ -7EobJO5IFVTJh4cv7vFxTJzSsRL8KFD4uzvh+nMCgYEAqY8NBYtIgNJA2B6C6hHF -+bG7v46434ZHFfGTmMQwzE4taVg7YRnzYESAlvK4bAP5ZXR90n7GRGFhrXzoMZ38 -r0bw/q9rV+ReGda7/Bjf7ciCKiq0RODcHtf4IaskjPXCoQRGJtgCPLhWPfld6g9v -/HTvO96xv9e3eG/PKSPog94= ------END PRIVATE KEY----- diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/common/diag.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/common/diag.go deleted file mode 100644 index bedaf3a8f..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/common/diag.go +++ /dev/null @@ -1,134 +0,0 @@ -package common - -import ( - "fmt" - "log" - "os" - "runtime" - "strconv" - "strings" - "time" -) - -func init(){ - log.SetPrefix("TRACE: ") - log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Llongfile) -} -func itoa(buf *[]byte, i int, wid int) { - // Assemble decimal in reverse order. - var b [20]byte - bp := len(b) - 1 - for i >= 10 || wid > 1 { - wid-- - q := i / 10 - b[bp] = byte('0' + i - q*10) - bp-- - i = q - } - // i < 10 - b[bp] = byte('0' + i) - *buf = append(*buf, b[bp:]...) -} - -func formatHeader(buf []byte, t time.Time, file string, line int) []byte{ - t = t.UTC() - year, month, day := t.Date() - itoa(&buf, year, 4) - buf = append(buf, '/') - itoa(&buf, int(month), 2) - buf = append(buf, '/') - itoa(&buf, day, 2) - buf = append(buf, ' ') - hour, min, sec := t.Clock() - itoa(&buf, hour, 2) - buf = append(buf, ':') - itoa(&buf, min, 2) - buf = append(buf, ':') - itoa(&buf, sec, 2) - buf = append(buf, '.') - itoa(&buf, t.Nanosecond()/1e3, 6) - buf = append(buf, ' ') - - short := file - for i := len(file) - 1; i > 0; i-- { - if file[i] == '/' { - short = file[i+1:] - break - } - } - file = short - buf = append(buf, file...) - buf = append(buf, ':') - itoa(&buf, line, -1) - return append(buf, ": "...) -} - -func CheckErr(res ...interface{}){ - for _,oriErr :=range res{ - if oriErr == nil{ - continue - } - switch oriErr.(type) { - case error: - err :=oriErr.(error) - s :=fmt.Sprintln(err) - _,file,line,ok:=runtime.Caller(1) - if ok { - info :="[CheckErr] " - buf :=make([]byte,0,1024) - buf=append(buf,info...) - buf = formatHeader(buf,time.Now(),file,line) - buf = append(buf, s...) - os.Stdout.Write(buf) - }else{ - fmt.Printf("%s %s",time.Now(),s) - } - os.Exit(2) - default: - } - } -} - - -func createNewFile(fileName string){ - err := os.Remove(fileName) - if err!=nil{ - log.Println(err) - } - fd,err:=os.Create(fileName) - if err!=nil{ - log.Fatal(err) - } - fd.Close() -} - -func GetGoid() int64 { - var ( - buf [64]byte - n = runtime.Stack(buf[:], false) - stk = strings.TrimPrefix(string(buf[:n]), "goroutine ") - ) - - idField := strings.Fields(stk)[0] - id, err := strconv.Atoi(idField) - if err != nil { - panic(fmt.Errorf("can not get goroutine id: %v", err)) - } - - return int64(id) -} - -func PrintType(a interface{}){ - switch a.(type) { - case int: - fmt.Println("type is int") - case string: - fmt.Println("type is string") - case float32: - fmt.Println("type is float32") - case float64: - fmt.Println("type is float64") - default: - fmt.Println("type is unknown type") - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/common/getOp.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/common/getOp.go deleted file mode 100644 index 32f25a9fa..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/common/getOp.go +++ /dev/null @@ -1,46 +0,0 @@ -package common - -import ( - "math/rand" - "reflect" - "runtime" - "strings" - "time" -) - -func init(){ - rand.Seed(time.Now().UnixNano()) -} - -func GetRandomString(n int)string{ - str := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - bytes :=[]byte(str) - result :=make([]byte,n) - for i:=0;i 0 { - return fields[size-1] - } - return "" -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/common/mysql.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/common/mysql.go deleted file mode 100644 index 6aae0d654..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/common/mysql.go +++ /dev/null @@ -1,357 +0,0 @@ -package common - -import ( - "database/sql" - "fmt" - "gitee.com/opengauss/openGauss-connector-go-pq" - ini "github.com/GaussKernel/ini-main" - "log" - "os" - "strconv" - "strings" - "sync" - "testing" -) - -var ( - parse_config =make(map[string]string) - onceDsnBase sync.Once - - t =&testing.T{} - SQL_QUERYTIME="select current_date" - //pg - DSN_PG_WIN = "host=127.0.0.1 port=5433 user=postgres password=Gauss_234 dbname=postgres sslmode=require" - DSN_PG_L_G="host=7.189.51.79 port=5431 user=gauss password=Gauss_234 dbname=gauss sslmode=disable" - //openGauss - DSN_OG_L_G = GetOGDsnBase() -) - - -func init() { - goPath := os.Getenv("GOPATH") - - //filePathPrefix :=d[:strings.Index(d, keyPath)] - filePathPrefix:=strings.Join([]string{goPath,"src","github.com","GaussKernel"},string(os.PathSeparator)) - iniPath := strings.Join([]string{filePathPrefix,"property.ini"},string(os.PathSeparator)) - cfg, err := ini.Load(iniPath) - if err!=nil{ - log.Fatal("load property error, ",err) - } - for _,key :=range cfg.Section("opengauss").Keys(){ - if len(key.Value())>0{ - parse_config[key.Name()]=key.Value() - } - } - sslPath :=strings.Join([]string{filePathPrefix,"certs"},string(os.PathSeparator)) - parse_config["sslkey"]=strings.Join([]string{sslPath,"postgresql.key"},string(os.PathSeparator)) - parse_config["sslcert"]=strings.Join([]string{sslPath,"postgresql.crt"},string(os.PathSeparator)) - parse_config["sslrootcert"]=strings.Join([]string{sslPath,"root.crt"},string(os.PathSeparator)) -} - -func GetOGDsnFull()(res string){ - for k,v :=range parse_config{ - res+=" "+k+"="+v - } - return -} -func GetOGDsnBase()(res string){ - baseOpt :=[]string{ - "host", - "port", - "user", - "password", - "dbname", - } - for _,opt :=range baseOpt{ - if v,ok:=parse_config[opt];ok{ - res+=" "+opt+"="+v - } - } - return -} -func GetOGUrlBase()(res string){ - return "" -} - -func GetPropertyUser()string{ - res,ok := parse_config["user"] - if ok{ - return res - } - log.Fatal("Your should set user in proterty.ini") - return "" -} -func GetPropertyPort()string{ - res,ok := parse_config["port"] - if ok{ - return res - } - log.Fatal("Your should set port in proterty.ini") - return "" -} -func GetPropertyDbName()string{ - res,ok := parse_config["dbname"] - if ok{ - return res - } - log.Fatal("Your should set hot in proterty.ini") - return "" -} -func GetPropertyHost()string{ - res,ok := parse_config["host"] - if ok{ - return res - } - log.Fatal("Your should set host in proterty.ini") - return "" -} - -func GetPropertyPassword()string{ - res,ok := parse_config["password"] - if ok{ - return res - } - log.Fatal("Your should set password in proterty.ini") - return "" -} - -//func GetPropertySSLKey()string{ -// return parse_config["sslkey"] -//} -//func GetPropertySSLCert()string{ -// return parse_config["sslcert"] -//} -//func GetPropertySSLRootCert()string{ -// return parse_config["sslrootcert"] -//} -//func GetPropertySSLDSN()string { -// return " sslkey="+GetPropertySSLKey()+" sslcert="+GetPropertySSLCert()+" sslrootcert="+GetPropertySSLRootCert() -//} - -func GetDefaultOGDB()(*sql.DB){ - db,err :=sql.Open("opengauss",GetOGDsnBase()) - CheckErr(err) - return db -} - -func TestDB(dv string, dsn string){ - db, err := sql.Open(dv, dsn) - if err != nil { - CheckErr(err) - } - defer db.Close() - var rc = 0 - err =db.QueryRow("select 1").Scan(&rc) - CheckErr(err) - if rc != 1 { - log.Fatal(dv,dsn,"["+dsn+"]query 1 wrong, rc=",rc) - return - } -} - -func TestConnExpect(dv string, dsn string, isExpectTrue bool){ - db, err := sql.Open(dv, dsn) - if err != nil { - if isExpectTrue { - log.Fatalf("this dsn \"%v\" should shout be ok, but error: %v",dsn,err) - } - return - } - defer db.Close() - var rc = 0 - err =db.QueryRow("select 1").Scan(&rc) - if err != nil { - if isExpectTrue { - log.Fatalf("this dsn \"%v\" should shout be ok, but error: %v",dsn,err) - } - return - } - if rc != 1 { - log.Fatal(dv,dsn,"["+dsn+"]query 1 wrong, rc=",rc) - return - } -} - -func PrintRowData(rows *sql.Rows){ - columns,err :=rows.Columns() - if err!=nil{ - log.Fatal("rows coulumns error",err) - } - cols:=len(columns) - - var scanResults = make([]interface{}, cols) - for i := 0; i < cols; i++ { - var s sql.NullString - scanResults[i] = &s - } - if err :=rows.Scan(scanResults...);err!=nil{ - log.Fatal("rows Scan error, ",err) - } - for i,key:=range columns{ - s := scanResults[i].(*sql.NullString) - if !s.Valid{ - fmt.Println(key+": NULL") - }else { - fmt.Println(key+": "+s.String) - } - } -} - -func IterScanRows(rows *sql.Rows)(idx int){ - for rows.Next(){ - idx++ - PrintRowData(rows) - } - return -} - -func IterScanDbTable(db *sql.DB, tname string)(idx int){ - sql :="select * from "+tname+" order by 1" - row,err:=db.Query(sql) - CheckErr(err) - return IterScanRows(row) -} - -func IterScanStmtTable(stmt *sql.Stmt, tname string)(idx int){ - sql :="select * from "+tname+" order by 1" - row,err:=stmt.Query(sql) - CheckErr(err) - return IterScanRows(row) -} - - -func IterScanTxTable(txn *sql.Tx, tname string)(idx int){ - sql :="select * from "+tname+" order by 1" - row,err := txn.Query(sql) - CheckErr(err) - return IterScanRows(row) -} - -type QueryInterface interface { - Query(query string, args ...interface{}) (*sql.Rows, error) -} - -func IterScanTable(sqlObject interface{}, tname string)(idx int){ - sql :="select * from "+tname+" order by 1" - if fQuery,ok:=sqlObject.(QueryInterface);ok{ - row,err := fQuery.Query(sql) - CheckErr(err) - return IterScanRows(row) - } else { - log.Fatal("cannot parse your input args") - } - return -1 -} - -func PrintQuery(db *sql.DB, sql string){ - rows,err:=db.Query(sql) - if err !=nil{ - //t.Fatal(err) - fmt.Println(err) - panic(err) - } - sqls :=strings.Split(sql,";") - tab_idx :=0 -LOOP: - tab_idx++ - fmt.Println("Query["+strconv.Itoa(tab_idx)+"]==> "+sqls[tab_idx-1]) - rowsCount :=IterScanRows(rows) - fmt.Println("<==Query["+strconv.Itoa(tab_idx)+"]"+" has "+strconv.Itoa(rowsCount)+" rows.") - if rows.NextResultSet(){ - goto LOOP - } -} - -func PrintTable(db *sql.DB, tables... string){ - for _,table := range tables{ - sql := "select * from "+table+" order by 1" - PrintQuery(db,sql) - } -} - -func PrintTableMeta(db *sql.DB, tableName, schameName string){ - getColumn:="SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, description," + - " CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey," + - " CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey" + - " FROM pg_attribute f" + - " JOIN pg_class c ON c.oid = f.attrelid JOIN pg_type t ON t.oid = f.atttypid" + - " LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum" + - " LEFT JOIN pg_description de ON f.attrelid=de.objoid AND f.attnum=de.objsubid" + - " LEFT JOIN pg_namespace n ON n.oid = c.relnamespace" + - " LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey)" + - " LEFT JOIN pg_class AS g ON p.confrelid = g.oid" + - " LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name" + - " WHERE n.nspname= s.table_schema AND c.relkind = 'r'::char AND c.relname = $1 AND s.table_schema = $2 AND f.attnum > 0 ORDER BY f.attnum;" - getIndex :="SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1 AND schemaname=$2" - row,err:=db.Query(getColumn,tableName,schameName) - CheckErr(err) - IterScanRows(row) - row,err=db.Query(getIndex,tableName,schameName) - CheckErr(err) - IterScanRows(row) -} - - -func GetTableRowCounts(db *sql.DB,table string)(rows int){ - sql :="select count(*) from "+table; - err :=db.QueryRow(sql).Scan(&rows) - if err!=nil{ - log.Fatal("query "+table+" row counts error",err) - } - return -} -func PrintTableRowCounts(db *sql.DB,table string){ - fmt.Printf("%s : %d\n",table,GetTableRowCounts(db,table)) -} - -func GetDriverErrorMessage(err error)string{ - if nerr,ok :=err.(*pq.Error);ok{ - return nerr.Message - } - return "" -} - -func TruncateTable(db *sql.DB,table string){ - sql :="select count(*) from "+table; - var rows int - err :=db.QueryRow(sql).Scan(&rows) - res,err:=db.Exec("truncate table "+table) - if err!=nil{ - log.Fatal("truncate table error,",err) - } - _,err = res.RowsAffected() - if err!=nil{ - log.Fatal("get rows affected error,",err) - } -} - -func CheckTabExists(db *sql.DB, schema,table string)bool{ - sql :="select count(*) from information_schema.columns where table_schema='"+schema+"' and table_name='"+table+"'" - var rowcount int - if err :=db.QueryRow(sql).Scan(&rowcount);err!=nil{ - fmt.Println(err) - return false - } - return rowcount==1 -} - -func PrintListenPort(db *sql.DB){ - var ips,port string - err :=db.QueryRow("select (select setting from pg_settings where name ='listen_addresses'), (select setting from pg_settings where name ='port')").Scan(&ips,&port) - if err!=nil{ - log.Fatal("PrintListenPort error,",err) - } - fmt.Println(ips,port) -} - -func SqlExec(db *sql.DB, sql string, args ...interface{}) { - r,err :=db.Exec(sql,args...) - if err !=nil{ - log.Fatal("sql["+sql+"] exec error,",err) - } - n,err:=r.RowsAffected() - if err!=nil{ - log.Fatal("sql["+sql+"] exec rows affect error,",err) - } - log.Println("sql["+sql+"] exec rows affect=",n) -} \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go.mod b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go.mod deleted file mode 100644 index 74125bf85..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go.mod +++ /dev/null @@ -1,25 +0,0 @@ -module github.com/GaussKernel - -go 1.17 - -require ( - gitee.com/opengauss/openGauss-connector-go-pq v0.0.0-00010101000000-000000000000 - github.com/go-xorm/xorm v0.0.0-00010101000000-000000000000 -) - -require ( - github.com/davecgh/go-spew v1.1.1 // indirect - github.com/kr/pretty v0.3.0 // indirect - github.com/pmezard/go-difflib v1.0.0 // indirect - golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 // indirect - golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect - gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c // indirect - xorm.io/builder v0.3.6 // indirect - xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb // indirect -) - -//replace gitee.com/opengauss/openGauss-connector-go-pq => ../../gitee.com/opengauss/openGauss-connector-go-pq - -replace github.com/go-xorm/xorm => ../../github.com/go-xorm/xorm - -replace gitee.com/opengauss/openGauss-connector-go-pq => ../../gitee.com/opengauss/openGauss-connector-go-pq diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go.sum b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go.sum deleted file mode 100644 index 8169dc987..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go.sum +++ /dev/null @@ -1,172 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= -cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o= -github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= -github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgservicefile v0.0.0-20200714003250-2b9c44734f2b/go.mod h1:vsD4gTJCa9TptPL8sPkXrLZ+hDuNrZCnj29CQpr4X1E= -github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/rogpeppe/go-internal v1.6.1 h1:/FiVV8dS/e+YqF2JvO3yXRFbBLTIuSDkuC7aBOAvL+k= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= -github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw= -google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= -xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/DML_test.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/DML_test.go deleted file mode 100644 index bee846c81..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/DML_test.go +++ /dev/null @@ -1,30 +0,0 @@ -package bench - -import ( - "database/sql" - "github.com/GaussKernel/common" - "log" - "testing" -) - -func TestDML(t *testing.T){ - insertRows :=100 - pool:=common.GetDefaultOGDB() - common.CheckErr(pool.Exec("drop table if exists testdml")) - common.CheckErr(pool.Exec("create table testdml(id int,name varchar(8000))")) - defer pool.Close() - st,err:=pool.Prepare("insert into testdml(id,name) values(:id,:name)") - if err!=nil{ - log.Fatal("insert error",err) - } - defer st.Close() - for i:=0;i= MAX_POOL_SIZE { - db.Close() - return - } - dbPoll <- db -} - -func initDB(t *testing.T) { - // 缓冲机制,相当于消息队列 - if len(dbPoll) == 0 { - // 如果长度为0,就定义一个redis.Conn类型长度为MAX_POOL_SIZE的channel - dbPoll = make(chan *sql.DB, MAX_POOL_SIZE) - go func() { - for i := 0; i < MAX_POOL_SIZE / 2; i++ { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - putDB(db) - } - } () - } -} - -func GetDB(t *testing.T) *sql.DB { - // 如果为空就初始化或者长度为零 - if dbPoll == nil || len(dbPoll) == 0 { - initDB(t) - } - return <- dbPoll -} - -func changeCount(num int, t *testing.T) { - db := GetDB(t) - - tx, err := db.Begin() // begin transaction - defer tx.Commit() // commit transaction - - res,_ := tx.Exec("update testTxLock set f3 = f3 + 100") - RowsAffected, err := res.RowsAffected() - if err != nil { - t.Fatal("res.RowsAffected==================Err") - } - if RowsAffected <= 0 { - fmt.Println("抢购失败") - } -} - -func TestConcurrency(t *testing.T) { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - - sqls := []string { - "drop table if exists testTxLock", - "create table testTxLock(f1 int, f2 varchar(20), f3 number, f4 timestamptz, f5 boolean)", - "insert into testTxLock values(1, '华为', 123.3, '2022-02-08 10:30:43.31 +08', true)", - } - - for i := 0; i <= 2; i++ { - _, err = db.Exec(sqls[i]) - if err != nil { - t.Fatal(err) - } - } - err = db.Close() - if err != nil { - t.Fatal(err) - } - - r := rand.New(rand.NewSource(time.Now().UnixNano())) - for i := 0; i < 10; i++ { - go changeCount(r.Intn(50), t) - go changeCount(r.Intn(50), t) - go changeCount(r.Intn(50), t) - go changeCount(r.Intn(50), t) - } - time.Sleep(3 * time.Second) -} \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/conn_parameter_test.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/conn_parameter_test.go deleted file mode 100644 index 99ddfb45a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/conn_parameter_test.go +++ /dev/null @@ -1,311 +0,0 @@ -package bench - -import ( - "database/sql" - "fmt" - "github.com/GaussKernel/common" - "log" - "math" - "regexp" - "strconv" - "strings" - "testing" -) - -func TestWrongPort(t *testing.T){ - var dsn="user=gauss dbname=gauss" - ports:=[]int{0,math.MaxUint16+1} - expectWrongMsg :="invalid port" - reg :=regexp.MustCompile(expectWrongMsg) - for _,port:=range ports{ - ndsn :=dsn+" port="+strconv.Itoa(port) - _,err :=sql.Open("opengauss",ndsn) - if err!=nil{ - errMsg :=err.Error() - if !reg.MatchString(errMsg){ - log.Fatal("wrong information change") - } - } else{ - log.Fatal("expect wrong") - } - - } -} - -func TestConnApplicationName(t *testing.T){ - dsn :=common.GetOGDsnBase() - db,err :=sql.Open("opengauss",dsn) - if err!=nil{ - log.Fatal("conn err,",err) - } - var appName string - err =db.QueryRow("select application_name from pg_stat_activity where pid=pg_backend_pid()").Scan(&appName) - if err!=nil{ - log.Fatal(err) - } - if(appName != "go-driver"){ //default name - log.Fatal("test application name fail") - } - db.Close() - testAppName:="test_application_Name" - dsn +=" application_name="+testAppName - db,err =sql.Open("opengauss",dsn) - if err!=nil{ - log.Fatal("conn err,",err) - } - err =db.QueryRow("select application_name from pg_stat_activity where pid=pg_backend_pid()").Scan(&appName) - if err!=nil{ - log.Fatal(err) - } - if appName != testAppName { - log.Fatal("test application name fail") - } -} - -func TestTargetSessionAttr(t *testing.T){ - attrs :=[]struct{ - attr string - expect bool - }{ - {"any", true}, - {"read-write", true}, - {"read-only", false}, - {"master",false}, - {"slave",false}, - {"preferSlave",false}, - } - dsn :=common.GetOGDsnBase() - for _,attr :=range attrs{ - ndsn :=dsn+" target_session_attrs=" + attr.attr - common.TestConnExpect("opengauss",ndsn, attr.expect) - } -} - -func TestBinaryParameters(t *testing.T){ - dsn :=common.GetOGDsnBase() - baseDB,err:=sql.Open("opengauss",dsn) - if err!=nil{ - log.Fatal(err) - } - defer baseDB.Close() - common.TruncateTable(baseDB,"people") - - binParams:=[]string{ - "yes", - "no", - } - disablePreparedBinaryResult:=[]string{ - "yes", - "no", - } - - for _,v1:=range binParams{ - for _,v2:=range disablePreparedBinaryResult{ - ndsn:=dsn+" binary_parameters="+v1+" disable_prepared_binary_result="+v2 - db,err :=sql.Open("opengauss",ndsn) - if err!=nil{ - log.Fatal("["+ndsn+"] error,",err) - } - stmt,err :=db.Prepare("insert into people values(:id,:name)") - if err!=nil{ - log.Fatal(err) - } - _,err = stmt.Exec(sql.Named("id",10000),sql.Named("name","test")) - if err!=nil{ - log.Fatal(err) - } - stmt.Close() - db.Close() - } - } - var rows int - baseDB.QueryRow("select count(*) from people where id=10000 and name='test'").Scan(&rows) - if rows != 4{ - log.Fatal("query res error") - } -} - -func TestErasePassword(t *testing.T){ - pws :=[]string{ - //"secretpw", - //"secretpw@", - //"@secretpw", - //"@secretpw@", - "secretpw\t", - "secretpw\n", - "secretpw\v", - "secretpw\f", - "secretpw,", - } - errorMode :=[]string{ - "xxx", - "abc=", - "abc", - "xxx\\", - "binary_parameters", - "binary_parameters=", - "binary_parameters=notval", - } - port:=common.GetPropertyPort() - dbname:=common.GetPropertyDbName() - host :=common.GetPropertyHost() - user:="notexist" - prefixDsn:="user="+user+" dbname="+dbname+" port="+port+" host="+host - prefixUrl:="opengauss://"+user+":" - suffixUrl:="@"+common.GetPropertyHost()+":"+common.GetPropertyPort()+"/"+common.GetPropertyDbName()+"?sslmode=disable&" - regPw := regexp.MustCompile("secretpw") - for _,emode :=range errorMode{ - for _,pw:=range pws{ - ndsn:=prefixDsn+emode+" password="+pw - nurl :=prefixUrl+pw+suffixUrl+emode - openinfo :=[]string{ - ndsn, - nurl, - } - for _,info :=range openinfo{ - db,err:=sql.Open("opengauss",info) - if err!=nil{ - s:=err.Error() - if regPw.MatchString(s){ - log.Fatal("Error, password erase fail, dataSourceName="+info) - } - continue - } - stmt,err :=db.Prepare("select 1") - if err!=nil{ - s:=err.Error() - if regPw.MatchString(s){ - log.Fatal("Error, password erase fail, dataSourceName="+info) - } - continue - } - stmt.Close() - db.Close() - } - } - } -} - -func TestErasePassword2(t *testing.T) { - sqlconn0 := "opengauss://test:Gauss_234@10.244.49.15:17777/godb?loggerLevel=debug1&password=Gauss_234&password= Gauss_234&password =Gauss_234&password = Gauss_234" - sqlconn00 := "opengauss://test:Gauss_234@10.244.49.15:17777/godb?loggerLevel=debug1&password='Gauss_234'&password= 'Gauss_234'&password ='Gauss_234'&password = 'Gauss_234'" - sqlconn1 := "opengauss://test:Gauss_234@10.244.49.15:17777/godb?loggerLevel=debug1&password=Gauss_234&sslpassword=Gauss_234&sslpassword= Gauss_234&sslpassword =Gauss_234&&sslpassword = Gauss_234" - sqlconn2 := "opengauss://test:Gauss_234@10.244.49.15:17777/godb?loggerLevel=debug1&password=Gauss_234&sslpassword='Gauss_234'&sslpassword= 'Gauss_234'&sslpassword ='Gauss_234'&&sslpassword = 'Gauss_234'" - sqlconns :=[]string{sqlconn00,sqlconn0, sqlconn1,sqlconn2} - for _,conn :=range sqlconns{ - _, err := sql.Open("opengauss", conn) - if err == nil { - log.Fatal("expect error") - } - errStr := err.Error() - f,err := regexp.MatchString("Gauss_234", errStr) - if err!=nil{ - log.Fatal(err) - } - if f { - log.Fatal("erase password failed. ", errStr) - } - } -} - -func TestConnParameter(t *testing.T) { - fmt.Println("********************No Runtime Parameter********************") - dsnStr := common.GetOGDsnBase() - - parameters := []string { - " connect_timeout=5", - " connect_timeout=-1", - " connect_timeout=0", - " connect_timeout=22.33", - " disable_prepared_binary_result=no", - " disable_prepared_binary_result=yes", - " disable_prepared_binary_result=NO", - " disable_prepared_binary_result=YES", - " disable_prepared_binary_result=n", - " disable_prepared_binary_result=y", - " disable_prepared_binary_result=N", - " disable_prepared_binary_result=Y", - " binary_parameters=yes", - " binary_parameters=YES", - " binary_parameters=NO", - " binary_parameters=no", - " binary_parameters=y", - " binary_parameters=Y", - " binary_parameters=n", - " binary_parameters=N", - } - - for _, param := range parameters { - db, err:= sql.Open("opengauss", dsnStr+param) - if err != nil { - arr := strings.Split(fmt.Sprintf("%v", err),":") - fmt.Printf("FAILED:%v, parse error:%v\n", param, arr[len(arr)-1]) - } else { - fmt.Printf("PARSE SUCCESS:%v\n", param) - db.Close() - } - } -} - -func TestConnRuntimeParameter(t *testing.T) { - fmt.Println("********************Runtime Parameter********************") - dsnStr := common.GetOGDsnBase() - - infos := []struct { - parameter, value string - } { - {" application_name", "go-test-api"}, - {" application_name", "default"}, - { " application_name", "123456"}, - {" datestyle", "SQL,YMD"}, - {" datestyle", "default"}, - {" datestyle", "SQL, YMD"}, - {" timezone", "GMT"}, - {" timezone", "ABC"}, - {" timezone", "+8"}, - {" timezone", "-05:00"}, - {" timezone", "+22"}, - {" timezone", "24"}, - {" timezone", "-23"}, - {" timezone", "25"}, - {" timezone", "-24"}, - {" timezone", "1234"}, - {" client_encoding", "SQL_ASCII"}, - {" client_encoding", "GBK"}, - {" client_encoding", "UTF8"}, - {" client_encoding", "ABCD"}, - {" client_encoding", "default"}, - {" client_encoding", "0"}, - {" search_path", "pqgotest"}, - {" search_path", "12345"}, - {" search_path", "default"}, - {" extra_float_digits", "0"}, - {" extra_float_digits", "-15"}, - {" extra_float_digits", "3"}, - {" extra_float_digits", "4"}, - {" extra_float_digits", "-16"}, - {" extra_float_digits", "3.4"}, - } - - for _, info := range infos { - dsn := dsnStr + info.parameter + "=" + info.value - db, err:= sql.Open("opengauss", dsn) - if err != nil { - arr := strings.Split(fmt.Sprintf("%v", err),":") - fmt.Printf("FAILED:%v, parse error:%v\n", info.parameter + "=" + info.value, arr[len(arr)-1]) - continue - } - - - var f1 string - err = db.QueryRow("show " + info.parameter).Scan(&f1) - if err != nil { - arr := strings.Split(fmt.Sprintf("%v", err),":") - fmt.Printf("FAILED:%v, parse error:%v\n", info.parameter + "=" + info.value, arr[len(arr)-1]) - } else { - fmt.Printf("RESULT: show%s: %s\n", info.parameter, f1) - } - - db.Close() - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/datatype_test.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/datatype_test.go deleted file mode 100644 index 5885cdfea..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/datatype_test.go +++ /dev/null @@ -1,968 +0,0 @@ -package bench - -import ( - "database/sql" - "fmt" - "github.com/GaussKernel/common" - "testing" - "time" -) - -func TestDatatype(t *testing.T){ - db :=common.GetDefaultOGDB() - common.CheckErr(db.Exec("drop table if exists mydata")) - common.CheckErr(db.Exec("create table mydata(a int, b varchar(100), d decimal(20,10),e tinyint, f boolean, g raw,k tsrange)")) - common.CheckErr(db.Exec("INSERT INTO mydata VALUES (1,'abc',1.234,127,false,'123456','[2010-01-01 14:30, 2010-01-01 15:30]')")) - common.CheckErr(db.Exec("INSERT INTO mydata VALUES (2,'abc',1.234,127,true,'223456','[2010-01-01 14:30, 2010-01-01 15:30]')")) - - common.IterScanDbTable(db,"mydata") - common.CheckErr(db.Exec("drop table if exists mydata")) - db.Close() -} - -func TestNumber(t *testing.T) { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testInteger", - "create table testInteger(f1 TINYINT, f2 SMALLINT, f3 INTEGER, f4 INTEGER, f5 BIGINT)", - "insert into testInteger values(255, 32767, 2147483647, 2147483647, 9223372036854775807)", - "insert into testInteger values(0, 0, 0, 0, 0)", - "insert into testInteger values(0, -32768, -2147483648, -2147483648, -9223372036854775808)", - "drop table if exists testNumeric", - "create table testNumeric(f1 numeric, f2 decimal(10,4), f3 number(20))", - "insert into testNumeric values(437164.41907403710, 71.6149329, 34819647147.0438148321)", - "drop table if exists testFloat", - "create table testFloat(f1 float4, f2 float8, f3 float, f4 binary_double, f5 dec(10,4), f6 integer(20,2))", - "insert into testFloat values(4164.5190, 34847.0438321, 437164.419403710, 71.6149329, 71.693291, 34819647147.04381321)", - "drop table if exists testSerial", - "create table testSerial(f1 smallserial, f2 serial, f3 bigserial)", - "insert into testSerial values(default, default, default)", - } - - for _, s := range sqls { - _, err = db.Exec(s) - if err != nil { - t.Fatal(err) - } - } - - infos := []struct { - descrip, datatype string - } { - {"----------result is golang string----------", "string"}, - {"\n----------result is golang interface{}----------", "interface{}"}, - {"\n----------result is golang []byte----------", "[]byte"}, - {"\n----------result is golang sql.RawBytes----------", "sql.RawBytes"}, - {"\n----------result is golang bool----------", "bool"}, - {"\n----------result is golang integer----------", "integer"}, - {"\n----------result is golang float----------", "float"}, - {"\n----------result is golang others----------", "others"}, - } - - queryInfos := []struct { - typeDescrip, querySql string - } { - {"********************Integer Datatype********************", "select *,i1toi2(123) from testInteger"}, - {"\n********************Numeric Datatype********************", "select *,* from testNumeric"}, - {"\n********************Float Datatype********************", "select * from testFloat"}, - {"\n********************Serial Datatype********************", "select *,* from testSerial"}, - } - - row, err := db.Query("select 1") - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for _, q := range queryInfos { - fmt.Println(q.typeDescrip) - - for _, info := range infos { - fmt.Println(info.descrip) - - row, err = db.Query(q.querySql) - if err != nil { - t.Fatal(err) - } - - for row.Next() { - switch info.datatype { - case "string": - var f1, f2, f3, f4, f5, f6 string - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "interface{}": - var f1, f2, f3, f4, f5, f6 interface{} - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "[]byte": - var f1, f2, f3, f4, f5, f6 []byte - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "sql.RawBytes": - var f1, f2, f3, f4, f5, f6 sql.RawBytes - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "bool": - var f1, f2, f3, f4, f5, f6 bool - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "integer": - var f1, f2, f3, f4, f5, f6 int64 - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "float": - var f1, f2, f3, f4, f5, f6 float64 - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "others": - var f1, f2, f3, f4, f5, f6 time.Time - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - } - } - - if err = row.Err(); err != nil { - t.Fatal(err) - } - } - } -} - -func TestDateAndTime(t *testing.T) { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testTime", - "create table testTime(f1 date, f2 time, f3 timetz, f4 timestamp, f5 timestamptz)", - "insert into testTime values('2022-01-28', '14:56:38.687146', '14:56:38.687146 GMT', '2022-01-28 14:56:38.687146', '2022-01-28 15:01:28.382264 GMT')", - "drop table if exists testInterval", - "create table testInterval(f1 smalldatetime, f2 interval day(1) to second(2), f3 interval hour(2), f4 reltime, f5 abstime)", - "insert into testInterval values('2022-01-28 15:01:00', interval '3' day, interval '2' year, '2022 year 1 mons 28 days 15:00:00', '2022-1-28 15:00:00 GMT')", - } - - for _, s := range sqls { - _, err = db.Exec(s) - if err != nil { - t.Fatal(err) - } - } - - infos := []struct { - descrip, datatype string - } { - {"----------result is golang string----------", "string"}, - {"\n----------result is golang interface{}----------", "interface{}"}, - {"\n----------result is golang []byte----------", "[]byte"}, - {"\n----------result is golang sql.RawBytes----------", "sql.RawBytes"}, - {"\n----------result is golang time.Time----------", "time.Time"}, - {"\n----------result is golang others----------", "others"}, - } - - queryInfos := []struct { - typeDescrip, querySql string - } { - {"********************Datetime Datatype********************", "select * from testTime"}, - {"\n********************Interval Datatype********************", "select * from testInterval"}, - } - - row, err := db.Query("select 1") - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for _, q := range queryInfos { - fmt.Println(q.typeDescrip) - - for _, info := range infos { - fmt.Println(info.descrip) - - row, err = db.Query(q.querySql) - if err != nil { - t.Fatal(err) - } - - for row.Next() { - switch info.datatype { - case "string": - var f1, f2, f3, f4, f5 string - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v\n", f1, f2, f3, f4, f5) - } - case "interface{}": - var f1, f2, f3, f4, f5 interface{} - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v\n", f1, f2, f3, f4, f5) - } - case "[]byte": - var f1, f2, f3, f4, f5 []byte - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v\n", f1, f2, f3, f4, f5) - } - case "sql.RawBytes": - var f1, f2, f3, f4, f5 sql.RawBytes - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v\n", f1, f2, f3, f4, f5) - } - case "time.Time": - var f1, f2, f3, f4, f5 time.Time - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v\n", f1, f2, f3, f4, f5) - } - case "others": - var f1, f2, f3, f4, f5 int64 - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v\n", f1, f2, f3, f4, f5) - } - } - } - - if err = row.Err(); err != nil { - t.Fatal(err) - } - } - } -} - -func TestMoneyAndBool(t *testing.T) { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testMoney", - "create table testMoney(f1 money)", - "insert into testMoney values(100), (2090.11), ('$12.432')", - "drop table if exists testBool", - "create table testBool(f1 bool)", - "insert into testBool values('t'),('no'),(6473)", - } - - for _, s := range sqls { - _, err = db.Exec(s) - if err != nil { - t.Fatal(err) - } - } - - infos := []struct { - descrip, datatype string - } { - {"----------result is golang string----------", "string"}, - {"\n----------result is golang interface{}----------", "interface{}"}, - {"\n----------result is golang []byte----------", "[]byte"}, - {"\n----------result is golang sql.RawBytes----------", "sql.RawBytes"}, - {"\n----------result is golang bool----------", "bool"}, - {"\n----------result is golang others----------", "others"}, - } - - queryInfos := []struct { - typeDescrip, querySql string - } { - {"********************Money Datatype********************", "select * from testMoney"}, - {"\n********************Bool Datatype********************", "select * from testBool"}, - } - - row, err := db.Query("select 1") - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for _, q := range queryInfos { - fmt.Println(q.typeDescrip) - - for _, info := range infos { - fmt.Println(info.descrip) - - row, err = db.Query(q.querySql) - if err != nil { - t.Fatal(err) - } - - for row.Next() { - switch info.datatype { - case "string": - var f1 string - err = row.Scan(&f1) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v\n", f1) - } - case "interface{}": - var f1 interface{} - err = row.Scan(&f1) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v\n", f1) - } - case "[]byte": - var f1 []byte - err = row.Scan(&f1) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v\n", f1) - } - case "sql.RawBytes": - var f1 sql.RawBytes - err = row.Scan(&f1) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v\n", f1) - } - case "bool": - var f1 bool - err = row.Scan(&f1) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v\n", f1) - } - case "others": - var f1 int64 - err = row.Scan(&f1) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v\n", f1) - } - } - } - - if err = row.Err(); err != nil { - t.Fatal(err) - } - } - } -} - -func TestCharacterAndBinary(t *testing.T) { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testCharacter", - "create table testCharacter(f1 char(1), f2 nchar(4), f3 varchar(10), f4 varchar2(10), f5 nvarchar2(2), f6 text, f7 clob)", - "insert into testCharacter values('a', '你', 'bbb', '2090.11', '中国', 'dgjqgdgfakgfekikgqif', 'dgjqgdgfakgfekikgqif')", - "insert into testCharacter values('1', 'true', '0', 'false', 'f', 'TRUE', 'FALSE')", - "insert into testCharacter values('1', '2000', '0', '4', '5', '6', '7')", - "drop table if exists testBinary", - "create table testBinary(f1 blob, f2 raw, f3 bytea)", - "insert into testBinary values('123','abc','deqde')", - } - - for _, s := range sqls { - _, err = db.Exec(s) - if err != nil { - t.Fatal(err) - } - } - - infos := []struct { - descrip, datatype string - } { - {"----------result is golang string----------", "string"}, - {"\n----------result is golang interface{}----------", "interface{}"}, - {"\n----------result is golang []byte----------", "[]byte"}, - {"\n----------result is golang sql.RawBytes----------", "sql.RawBytes"}, - {"\n----------result is golang bool----------", "bool"}, - {"\n----------result is golang integer----------", "integer"}, - {"\n----------result is golang float----------", "float"}, - {"\n----------result is golang others----------", "others"}, - } - - queryInfos := []struct { - typeDescrip, querySql string - } { - {"********************Character Datatype********************", "select * from testCharacter"}, - {"\n********************Binary Datatype********************", "select *,*,f1 from testBinary"}, - } - - row, err := db.Query("select 1") - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for _, q := range queryInfos { - fmt.Println(q.typeDescrip) - - for _, info := range infos { - fmt.Println(info.descrip) - - row, err = db.Query(q.querySql) - if err != nil { - t.Fatal(err) - } - - for row.Next() { - switch info.datatype { - case "string": - var f1, f2, f3, f4, f5, f6, f7 string - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6, &f7) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v, F7:%v\n", f1, f2, f3, f4, f5, f6, f7) - } - case "interface{}": - var f1, f2, f3, f4, f5, f6, f7 interface{} - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6, &f7) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v, F7:%v\n", f1, f2, f3, f4, f5, f6, f7) - } - case "[]byte": - var f1, f2, f3, f4, f5, f6, f7 []byte - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6, &f7) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v, F7:%v\n", f1, f2, f3, f4, f5, f6, f7) - } - case "sql.RawBytes": - var f1, f2, f3, f4, f5, f6, f7 sql.RawBytes - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6, &f7) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v, F7:%v\n", f1, f2, f3, f4, f5, f6, f7) - } - case "bool": - var f1, f2, f3, f4, f5, f6, f7 bool - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6, &f7) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v, F7:%v\n", f1, f2, f3, f4, f5, f6, f7) - } - case "integer": - var f1, f2, f3, f4, f5, f6, f7 int64 - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6, &f7) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v, F7:%v\n", f1, f2, f3, f4, f5, f6, f7) - } - case "float": - var f1, f2, f3, f4, f5, f6, f7 float64 - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6, &f7) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v, F7:%v\n", f1, f2, f3, f4, f5, f6, f7) - } - case "others": - var f1, f2, f3, f4, f5, f6, f7 time.Time - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6, &f7) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v, F7:%v\n", f1, f2, f3, f4, f5, f6, f7) - } - } - } - - if err = row.Err(); err != nil { - t.Fatal(err) - } - } - } -} - -func TestGeometry(t *testing.T) { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testGeometry", - "create table testGeometry(f1 point, f2 lseg, f3 box, f4 path, f5 polygon, f6 circle)", - "insert into testGeometry values('1,2', '1,2,3,4', '1,1,2,2', '1,0,2,0,3,4', '1,0,2,0,3,4', '0,0,2')", - } - - for _, s := range sqls { - _, err = db.Exec(s) - if err != nil { - t.Fatal(err) - } - } - - infos := []struct { - descrip, datatype string - } { - {"----------result is golang string----------", "string"}, - {"\n----------result is golang interface{}----------", "interface{}"}, - {"\n----------result is golang []byte----------", "[]byte"}, - {"\n----------result is golang sql.RawBytes----------", "sql.RawBytes"}, - {"\n----------result is golang others----------", "others"}, - } - - fmt.Println("********************Geometry Datatype********************") - row, err := db.Query("select 1") - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for _, info := range infos { - fmt.Println(info.descrip) - - row, err = db.Query("select * from testGeometry") - if err != nil { - t.Fatal(err) - } - - for row.Next() { - switch info.datatype { - case "string": - var f1, f2, f3, f4, f5, f6 string - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "interface{}": - var f1, f2, f3, f4, f5, f6 interface{} - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "[]byte": - var f1, f2, f3, f4, f5, f6 []byte - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "sql.RawBytes": - var f1, f2, f3, f4, f5, f6 sql.RawBytes - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "others": - var f1, f2, f3, f4, f5, f6 time.Time - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - } - } - - if err = row.Err(); err != nil { - t.Fatal(err) - } - } -} - -func TestMacBitTS(t *testing.T) { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testMac", - "create table testMac(f1 cidr, f2 inet, f3 macaddr)", - "insert into testMac values('192.168/24', '192.168.1.5/8', '08:00:2b:01:02:03')", - "insert into testMac values('192.1', '192.1.2.1', '08002b:010203')", - "drop table if exists testBit", - "create table testBit(f1 serial, f2 bit(3), f3 bit varying(5))", - "insert into testBit values(default, B'101', B'1011')", - "insert into testBit values(default, B'10'::bit(3), B'01')", - "drop table if exists testTs", - "create table testTs(f1 serial, f2 tsvector, f3 tsquery)", - "insert into testTs values(default, 'a fat cat sat on a mat and ate a fat rat', 'fat & rat')", - } - - for _, s := range sqls { - _, err = db.Exec(s) - if err != nil { - t.Fatal(err) - } - } - - infos := []struct { - descrip, datatype string - } { - {"----------result is golang string----------", "string"}, - {"\n----------result is golang interface{}----------", "interface{}"}, - {"\n----------result is golang []byte----------", "[]byte"}, - {"\n----------result is golang sql.RawBytes----------", "sql.RawBytes"}, - {"\n----------result is golang others----------", "others"}, - } - - queryInfos := []struct { - typeDescrip, querySql string - } { - {"********************NetAddr Datatype********************", "select * from testMac"}, - {"\n********************BitStr Datatype********************", "select * from testBit"}, - {"\n********************TextSearch Datatype********************", "select * from testTs"}, - } - - row, err := db.Query("select 1") - if err != nil { - t.Fatal(err) - } - defer row.Close() - for _, q := range queryInfos { - fmt.Println(q.typeDescrip) - - for _, info := range infos { - fmt.Println(info.descrip) - - row, err = db.Query(q.querySql) - if err != nil { - t.Fatal(err) - } - - for row.Next() { - switch info.datatype { - case "string": - var f1, f2, f3 string - err = row.Scan(&f1, &f2, &f3) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v\n", f1, f2, f3) - } - case "interface{}": - var f1, f2, f3 interface{} - err = row.Scan(&f1, &f2, &f3) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v\n", f1, f2, f3) - } - case "[]byte": - var f1, f2, f3 []byte - err = row.Scan(&f1, &f2, &f3) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v\n", f1, f2, f3) - } - case "sql.RawBytes": - var f1, f2, f3 sql.RawBytes - err = row.Scan(&f1, &f2, &f3) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v\n", f1, f2, f3) - } - case "others": - var f1, f2, f3 time.Time - err = row.Scan(&f1, &f2, &f3) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v\n", f1, f2, f3) - } - } - } - - if err = row.Err(); err != nil { - t.Fatal(err) - } - } - } -} - -func TestRangeAndJson(t *testing.T) { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testRange", - "create table testRange(f1 int4range, f2 int8range, f3 numrange, f4 tsrange, f5 tstzrange, f6 daterange)", - "insert into testRange values('[-1,10]', '[-2910,7738)', '(367.431, 731.431]', '(2010-01-01 14:30, 2010-01-04 15:30)', " + - "'[2022-01-28 15:01:28.382264 GMT , 2022-01-30 15:01:28.382264 GMT]', '[2022-01-28, 2022-01-31]')", - "drop table if exists testJson", - "create table testJson(f1 json, f2 jsonb, f3 json, f4 jsonb, f5 json, f6 jsonb)", - "insert into testJson values(' [1, \" a \", {\"a\" :1 }] ', ' [1, \" a \", {\"a\" :1 }] ', " + - "'{\"a\" : 1, \"a\" : 2}', '{\"a\" : 1, \"a\" : 2}', " + - "'{\"aa\" : 1, \"b\" : 2, \"a\" : 3}', '{\"aa\" : 1, \"b\" : 2, \"a\" : 3}')", - } - - for _, s := range sqls { - _, err = db.Exec(s) - if err != nil { - t.Fatal(err) - } - } - - infos := []struct { - descrip, datatype string - } { - {"----------result is golang string----------", "string"}, - {"\n----------result is golang interface{}----------", "interface{}"}, - {"\n----------result is golang []byte----------", "[]byte"}, - {"\n----------result is golang sql.RawBytes----------", "sql.RawBytes"}, - {"\n----------result is golang others----------", "others"}, - } - - queryInfos := []struct { - typeDescrip, querySql string - } { - {"********************Range Datatype********************", "select * from testRange"}, - {"\n********************Json Datatype********************", "select * from testJson"}, - } - - row, err := db.Query("select 1") - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for _, q := range queryInfos { - fmt.Println(q.typeDescrip) - - for _, info := range infos { - fmt.Println(info.descrip) - - row, err = db.Query(q.querySql) - if err != nil { - t.Fatal(err) - } - - for row.Next() { - switch info.datatype { - case "string": - var f1, f2, f3, f4, f5, f6 string - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "interface{}": - var f1, f2, f3, f4, f5, f6 interface{} - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "[]byte": - var f1, f2, f3, f4, f5, f6 []byte - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "sql.RawBytes": - var f1, f2, f3, f4, f5, f6 sql.RawBytes - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - case "others": - var f1, f2, f3, f4, f5, f6 bool - err = row.Scan(&f1, &f2, &f3, &f4, &f5, &f6) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v, F5:%v, F6:%v\n", f1, f2, f3, f4, f5, f6) - } - } - } - - if err = row.Err(); err != nil { - t.Fatal(err) - } - } - } -} - -func TestOthers(t *testing.T) { - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testOthers", - "create table testOthers(f1 uuid, f2 hash16, f3 hash32, set hll)", - "insert into testOthers values('A0EEBC99-9C0B-4EF8-BB6D-6BB9BD380A11', 'e697da2eaa3a775b', '685847ed1fe38e18f6b0e2b18c00edee', hll_empty())", - } - - for _, s := range sqls { - _, err = db.Exec(s) - if err != nil { - t.Fatal(err) - } - } - - infos := []struct { - descrip, datatype string - } { - {"----------result is golang string----------", "string"}, - {"\n----------result is golang interface{}----------", "interface{}"}, - {"\n----------result is golang []byte----------", "[]byte"}, - {"\n----------result is golang sql.RawBytes----------", "sql.RawBytes"}, - {"\n----------result is golang others----------", "others"}, - } - - fmt.Println("********************Other Datatype********************") - - row, err := db.Query("select 1") - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for _, info := range infos { - fmt.Println(info.descrip) - - row, err = db.Query("select * from testOthers") - if err != nil { - t.Fatal(err) - } - - for row.Next() { - switch info.datatype { - case "string": - var f1, f2, f3, f4 string - err = row.Scan(&f1, &f2, &f3, &f4) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v\n", f1, f2, f3, f4) - } - case "interface{}": - var f1, f2, f3, f4 interface{} - err = row.Scan(&f1, &f2, &f3, &f4) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v\n", f1, f2, f3, f4) - } - case "[]byte": - var f1, f2, f3, f4 []byte - err = row.Scan(&f1, &f2, &f3, &f4) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v\n", f1, f2, f3, f4) - } - case "sql.RawBytes": - var f1, f2, f3, f4 sql.RawBytes - err = row.Scan(&f1, &f2, &f3, &f4) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v\n", f1, f2, f3, f4) - } - case "others": - var f1, f2, f3, f4 bool - err = row.Scan(&f1, &f2, &f3, &f4) - if err != nil { - fmt.Println(err) - } else { - fmt.Printf("F1:%v, F2:%v, F3:%v, F4:%v\n", f1, f2, f3, f4) - } - } - } - - if err = row.Err(); err != nil { - t.Fatal(err) - } - } -} \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/db_test.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/db_test.go deleted file mode 100644 index cfb1561e3..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/db_test.go +++ /dev/null @@ -1,171 +0,0 @@ -package bench - -import ( - "context" - "database/sql" - "fmt" - "github.com/GaussKernel/common" - "strings" - "testing" - "time" -) - -func TestDBExec(t *testing.T) { - fmt.Println("********************DB Exec********************") - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - err = db.Ping() - if err != nil { - t.Fatal(err) - } - - sqls := []string { - "drop table if exists testExec", - "create table testExec(f1 int, f2 varchar(20), f3 number, f4 timestamptz, f5 boolean)", - "insert into testExec values(1, 'abcdefg', 123.3, '2022-02-08 10:30:43.31 +08', true)", - "insert into testExec values(:f1, :f2, :f3, :f4, :f5)", - } - - inF1 := []int{2, 3, 4, 5, 6} - intF2 := []string{"hello world", "华为", "北京2022冬奥会", "nanjing", "研究所"} - intF3 := []float64{641.43, 431.54, 5423.52, 665537.63, 6503.1} - intF4 := []time.Time{ - time.Date(2022, 2, 8, 10, 35, 43, 623431, time.Local), - time.Date(2022, 2, 10, 19, 11, 54, 353431, time.Local), - time.Date(2022, 2, 12, 6, 11, 15, 636431, time.Local), - time.Date(2022, 2, 14, 4, 51, 22, 747653, time.Local), - time.Date(2022, 2, 16, 13, 45, 55, 674636, time.Local), - } - intF5 := []bool{false, true, false, true, true} - - for _, str := range sqls { - if strings.Contains(str, ":f") { - for i, _ := range inF1 { - _, err := db.Exec(str, inF1[i], intF2[i], intF3[i], intF4[i], intF5[i]) - if err != nil { - t.Fatal(err) - } - } - } else { - _, err = db.Exec(str) - if err != nil { - t.Fatal(err) - } - } - } - - var f1 int - var f2 string - var f3 float64 - var f4 time.Time - var f5 bool - err = db.QueryRow("select * from testExec").Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - - row, err :=db.Query("select * from testExec where f1 > :1", 1) - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for row.Next() { - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - } -} - -func TestDBExecContext(t *testing.T) { - fmt.Println("********************DB ExecContext********************") - ctx := context.Background() - ctx2SecondTimeout, cancelFunc2SecondTimeout := context.WithTimeout(ctx, 2 * time.Second) - defer cancelFunc2SecondTimeout() - - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - // Ping database connection with 2 second timeout - err = db.PingContext(ctx2SecondTimeout) - if err != nil { - t.Fatal(err) - } - - sqls := []string { - "drop table if exists testExecContext", - "create table testExecContext(f1 int, f2 varchar(20), f3 number, f4 timestamptz, f5 boolean)", - "insert into testExecContext values(1, 'abcdefg', 123.3, '2022-02-08 10:30:43.31 +08', true)", - "insert into testExecContext values(:f1, :f2, :f3, :f4, :f5)", - } - - inF1 := []int{2, 3, 4, 5, 6} - intF2 := []string{"hello world", "华为", "北京2022冬奥会", "nanjing", "研究所"} - intF3 := []float64{641.43, 431.54, 5423.52, 665537.63, 6503.1} - intF4 := []time.Time{ - time.Date(2022, 2, 8, 10, 35, 43, 623431, time.Local), - time.Date(2022, 2, 10, 19, 11, 54, 353431, time.Local), - time.Date(2022, 2, 12, 6, 11, 15, 636431, time.Local), - time.Date(2022, 2, 14, 4, 51, 22, 747653, time.Local), - time.Date(2022, 2, 16, 13, 45, 55, 674636, time.Local), - } - intF5 := []bool{false, true, false, true, true} - - for _, str := range sqls { - if strings.Contains(str, ":f") { - for i, _ := range inF1 { - _, err := db.ExecContext(ctx2SecondTimeout, str, inF1[i], intF2[i], intF3[i], intF4[i], intF5[i]) - if err != nil { - t.Fatal(err) - } - } - } else { - _, err = db.ExecContext(ctx2SecondTimeout, str) - if err != nil { - t.Fatal(err) - } - } - } - - var f1 int - var f2 string - var f3 float64 - var f4 time.Time - var f5 bool - err = db.QueryRowContext(ctx2SecondTimeout, "select * from testExecContext").Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - - row, err :=db.QueryContext(ctx2SecondTimeout, "select * from testExecContext where f1 > :1", 1) - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for row.Next() { - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - } -} - diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/ping_test.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/ping_test.go deleted file mode 100644 index 9e6c038f2..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/ping_test.go +++ /dev/null @@ -1,60 +0,0 @@ -package bench - -import ( - "context" - "database/sql" - "flag" - . "github.com/GaussKernel/common" - "log" - "os" - "os/signal" - "testing" - "time" -) - -func TestPing(t *testing.T) { - id := flag.Int64("id", 1, "person ID to find") - flag.Parse() - - pool :=GetDefaultOGDB() - defer pool.Close() - CheckErr(pool.Exec("drop table if exists testping")) - CheckErr(pool.Exec("create table testping(id int,name varchar(8000))")) - CheckErr(pool.Exec("insert into testping values(:id,'abc')",*id)) - ctx, stop := context.WithCancel(context.Background()) - defer stop() - - appSignal := make(chan os.Signal, 3) - signal.Notify(appSignal, os.Interrupt) - - go func() { - select { - case <-appSignal: - stop() - } - }() - Ping(pool,ctx) - Query(pool, ctx, *id) - row,err := pool.Query("select * from testping") - CheckErr(err) - IterScanRows(row) - CheckErr(pool.Exec("drop table testping")) -} - -func Ping(pool *sql.DB,ctx context.Context) { - ctx, cancel := context.WithTimeout(ctx, 1*time.Second) - defer cancel() - - if err := pool.PingContext(ctx); err != nil { - log.Fatalf("unable to connect to database: %v", err) - } -} - -func Query(pool *sql.DB, ctx context.Context, id int64) { - ctx, cancel := context.WithTimeout(ctx, 5000*time.Second) - defer cancel() - - row,err := pool.QueryContext(ctx, "select p.name from testping as p where p.id = :id", sql.Named("id", id)) - CheckErr(err) - IterScanRows(row) -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/row_test.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/row_test.go deleted file mode 100644 index 9215aa99a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/row_test.go +++ /dev/null @@ -1,174 +0,0 @@ -package bench - -import ( - "database/sql" - "fmt" - "github.com/GaussKernel/common" - "strings" - "testing" - "time" -) - -func TestRows(t *testing.T) { - fmt.Println("********************Query with Row********************") - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testRows", - "create table testRows(f1 int, f2 varchar(20), f3 number, f4 timestamptz, f5 boolean)", - "insert into testRows values(1, 'abcdefg', 123.3, '2022-02-08 10:30:43.31 +08', true)", - "insert into testRows values(:f1, :f2, :f3, :f4, :f5)", - } - - inF1 := []int{2, 3, 4, 5, 6} - intF2 := []string{"hello world", "华为", "北京2022冬奥会", "nanjing", "研究所"} - intF3 := []float64{641.43, 431.54, 5423.52, 665537.63, 6503.1} - intF4 := []time.Time{ - time.Date(2022, 2, 8, 10, 35, 43, 623431, time.Local), - time.Date(2022, 2, 10, 19, 11, 54, 353431, time.Local), - time.Date(2022, 2, 12, 6, 11, 15, 636431, time.Local), - time.Date(2022, 2, 14, 4, 51, 22, 747653, time.Local), - time.Date(2022, 2, 16, 13, 45, 55, 674636, time.Local), - } - intF5 := []bool{false, true, false, true, true} - - for _, str := range sqls { - if strings.Contains(str, ":f") { - for i, _ := range inF1 { - _, err := db.Exec(str, inF1[i], intF2[i], intF3[i], intF4[i], intF5[i]) - if err != nil { - t.Fatal(err) - } - } - } else { - _, err = db.Exec(str) - if err != nil { - t.Fatal(err) - } - } - } - - var f1 int - var f2 string - var f3 float64 - var f4 time.Time - var f5 bool - err = db.QueryRow("select * from testRows").Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - - row, err :=db.Query("select * from testRows where f1 > :1", 1) - if err != nil { - t.Fatal(err) - } - defer row.Close() - - column, err := row.Columns() - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("The name of columns is ") - for _, c := range column { - fmt.Printf("%v ",c) - } - } - - fmt.Println("\n********************Query with Rows********************") - for row.Next() { - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - } - - if row.Err() != nil { - t.Fatal(err) - } -} - -func TestColumnType(t *testing.T) { - fmt.Println("********************Get ColumnType********************") - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testRows", - "create table testRows(f1 int, f2 VARCHAR(20), f3 number(20,4), f4 timestamptz, f5 boolean, f6 float, f7 money, f8 polygon, f9 bytea)", - "insert into testRows values(1, 'abcdefg', 123.3, '2022-02-08 10:30:43.31 +08', true, 123.3, '$12.432', '1,0,2,0,3,4', 'deqde')", - "insert into testRows values(:f1, :f2, :f3, :f4, :f5, :f6, :f7, :f8, :f9)", - } - - inF1 := []int{2, 3, 4, 5, 6} - intF2 := []string{"hello world", "华为", "北京2022冬奥会", "nanjing", "研究所"} - intF3 := []float64{641.43, 431.54, 5423.52, 665537.63, 6503.1} - intF4 := []time.Time{ - time.Date(2022, 2, 8, 10, 35, 43, 623431, time.Local), - time.Date(2022, 2, 10, 19, 11, 54, 353431, time.Local), - time.Date(2022, 2, 12, 6, 11, 15, 636431, time.Local), - time.Date(2022, 2, 14, 4, 51, 22, 747653, time.Local), - time.Date(2022, 2, 16, 13, 45, 55, 674636, time.Local), - } - intF5 := []bool{false, true, false, true, true} - intF6 := []float32{641.43, 431.54, 5423.52, 665537.63, 6503.1} - intF7 := []string{"123.11", "$1234.41", "11.41", "41.41", "$12.525"} - intF8 := []string{"1,2,3,4,5,6", "2,3,4,5,6,7", "3,4,5,6,7,8", "4,5,6,7,8,9", "1,3,5,7,9,0", "2,4,6,8,0,2"} - intF9 := []string{"rwr", "fafa", "dfaj", "fhfijheio", "fnak"} - - for _, str := range sqls { - if strings.Contains(str, ":f") { - for i, _ := range inF1 { - _, err := db.Exec(str, inF1[i], intF2[i], intF3[i], intF4[i], intF5[i], intF6[i], intF7[i], intF8[i], intF9[i]) - if err != nil { - t.Fatal(err) - } - } - } else { - _, err = db.Exec(str) - if err != nil { - t.Fatal(err) - } - } - } - - row, err :=db.Query("select * from testRows where f1 > :1", 1) - if err != nil { - t.Fatal(err) - } - defer row.Close() - - ct, err := row.ColumnTypes() - if err != nil { - t.Fatal(err) - } else { - for _, c := range ct { - name := c.Name() - typeName := c.DatabaseTypeName() - fmt.Printf("Name is %v, DatabaseTypeName is %v. ", name, typeName) - precision, scale, isDecimal := c.DecimalSize() - if isDecimal { - fmt.Printf("Decimal precision is %v, scale is %v. ", precision, scale) - } - length, isLen := c.Length() - if isLen { - fmt.Printf("Sting length is %v. ",length) - } - scanType := c.ScanType() - fmt.Printf("ScanType is %v.\n", scanType) - } - } - -} \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/ssl_conn_test.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/ssl_conn_test.go deleted file mode 100644 index ae245c967..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/ssl_conn_test.go +++ /dev/null @@ -1,22 +0,0 @@ -package bench - -import ( - "github.com/GaussKernel/common" - "testing" -) - -func TestSSL(t *testing.T){ - var dsn=common.GetOGDsnBase() - sslmodes :=[]string{ - "disable", - "prefer", - "allow", - "require", - "verify-ca", - //"verify-full", - } - for _,sslmode:= range sslmodes{ - fdsn :=dsn+" sslmode="+sslmode - common.TestConnExpect("opengauss",fdsn,true) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/stmt_test.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/stmt_test.go deleted file mode 100644 index 362eb0e10..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test/stmt_test.go +++ /dev/null @@ -1,185 +0,0 @@ -package bench - -import ( - "context" - "database/sql" - "fmt" - "github.com/GaussKernel/common" - "strings" - "testing" - "time" -) - -func TestStmtExec(t *testing.T) { - fmt.Println("********************Stmt Exec********************") - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - sqls := []string { - "drop table if exists testStmtExec", - "create table testStmtExec(f1 int, f2 varchar(20), f3 number, f4 timestamptz, f5 boolean)", - "insert into testStmtExec values(1, 'abcdefg', 123.3, '2022-02-08 10:30:43.31 +08', true)", - "insert into testStmtExec values(:f1, :f2, :f3, :f4, :f5)", - } - - inF1 := []int{2, 3, 4, 5, 6} - intF2 := []string{"hello world", "华为", "北京2022冬奥会", "nanjing", "研究所"} - intF3 := []float64{641.43, 431.54, 5423.52, 665537.63, 6503.1} - intF4 := []time.Time{ - time.Date(2022, 2, 8, 10, 35, 43, 623431, time.Local), - time.Date(2022, 2, 10, 19, 11, 54, 353431, time.Local), - time.Date(2022, 2, 12, 6, 11, 15, 636431, time.Local), - time.Date(2022, 2, 14, 4, 51, 22, 747653, time.Local), - time.Date(2022, 2, 16, 13, 45, 55, 674636, time.Local), - } - intF5 := []bool{false, true, false, true, true} - - for _, str := range sqls { - s, err := db.Prepare(str) - if err != nil { - t.Fatal(err) - } - if strings.Contains(str, ":f") { - for i, _ := range inF1 { - _, err := s.Exec(inF1[i], intF2[i], intF3[i], intF4[i], intF5[i]) - if err != nil { - t.Fatal(err) - } - } - } else { - _, err = s.Exec() - if err != nil { - t.Fatal(err) - } - } - } - - var f1 int - var f2 string - var f3 float64 - var f4 time.Time - var f5 bool - s, err := db.Prepare("select * from testStmtExec") - if err != nil { - t.Fatal(err) - } - defer s.Close() - err =s.QueryRow().Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - - s, err = db.Prepare("select * from testStmtExec where f1 > :1") - if err != nil { - t.Fatal(err) - } - row, err :=s.Query(1) - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for row.Next() { - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - } -} - -func TestStmtExecCtx(t *testing.T) { - fmt.Println("********************Stmt ExecContext********************") - ctx := context.Background() - ctx2SecondTimeout, cancelFunc2SecondTimeout := context.WithTimeout(ctx, 2 * time.Second) - defer cancelFunc2SecondTimeout() - - dsn := common.GetOGDsnBase() - db, err:= sql.Open("opengauss", dsn) - if err != nil { - t.Fatal(err) - } - defer db.Close() - - sqls := []string { - "drop table if exists testStmtExecCtx", - "create table testStmtExecCtx(f1 int, f2 varchar(20), f3 number, f4 timestamptz, f5 boolean)", - "insert into testStmtExecCtx values(1, 'abcdefg', 123.3, '2022-02-08 10:30:43.31 +08', true)", - "insert into testStmtExecCtx values(:f1, :f2, :f3, :f4, :f5)", - } - - inF1 := []int{2, 3, 4, 5, 6} - intF2 := []string{"hello world", "华为", "北京2022冬奥会", "nanjing", "研究所"} - intF3 := []float64{641.43, 431.54, 5423.52, 665537.63, 6503.1} - intF4 := []time.Time{ - time.Date(2022, 2, 8, 10, 35, 43, 623431, time.Local), - time.Date(2022, 2, 10, 19, 11, 54, 353431, time.Local), - time.Date(2022, 2, 12, 6, 11, 15, 636431, time.Local), - time.Date(2022, 2, 14, 4, 51, 22, 747653, time.Local), - time.Date(2022, 2, 16, 13, 45, 55, 674636, time.Local), - } - intF5 := []bool{false, true, false, true, true} - - for _, str := range sqls { - s, err := db.PrepareContext(ctx2SecondTimeout, str) - if err != nil { - t.Fatal(err) - } - if strings.Contains(str, ":f") { - for i, _ := range inF1 { - _, err := s.ExecContext(ctx2SecondTimeout, inF1[i], intF2[i], intF3[i], intF4[i], intF5[i]) - if err != nil { - t.Fatal(err) - } - } - } else { - _, err = s.ExecContext(ctx2SecondTimeout) - if err != nil { - t.Fatal(err) - } - } - } - - var f1 int - var f2 string - var f3 float64 - var f4 time.Time - var f5 bool - s, err := db.PrepareContext(ctx2SecondTimeout, "select * from testStmtExecCtx") - if err != nil { - t.Fatal(err) - } - defer s.Close() - - err = s.QueryRowContext(ctx2SecondTimeout).Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - - s, err = db.PrepareContext(ctx2SecondTimeout, "select * from testStmtExecCtx where f1 > :1") - if err != nil { - t.Fatal(err) - } - row, err :=s.QueryContext(ctx2SecondTimeout, 1) - if err != nil { - t.Fatal(err) - } - defer row.Close() - - for row.Next() { - err = row.Scan(&f1, &f2, &f3, &f4, &f5) - if err != nil { - t.Fatal(err) - } else { - fmt.Printf("f1:%v, f2:%v, f3:%v, f4:%v, f5:%v\n", f1, f2, f3, f4, f5) - } - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/DML_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/DML_test.go.out deleted file mode 100644 index 7ef22e9a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/DML_test.go.out +++ /dev/null @@ -1 +0,0 @@ -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/MulitSQL_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/MulitSQL_test.go.out deleted file mode 100644 index 7ef22e9a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/MulitSQL_test.go.out +++ /dev/null @@ -1 +0,0 @@ -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/Notice_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/Notice_test.go.out deleted file mode 100644 index 7ef22e9a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/Notice_test.go.out +++ /dev/null @@ -1 +0,0 @@ -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/SQLCancel_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/SQLCancel_test.go.out deleted file mode 100644 index 7ef22e9a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/SQLCancel_test.go.out +++ /dev/null @@ -1 +0,0 @@ -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/TempTable_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/TempTable_test.go.out deleted file mode 100644 index cbbd0ceac..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/TempTable_test.go.out +++ /dev/null @@ -1,3 +0,0 @@ -count: 10 -count: 10 -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/Tx_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/Tx_test.go.out deleted file mode 100644 index 42074d3ad..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/Tx_test.go.out +++ /dev/null @@ -1,166 +0,0 @@ -testtx1 : 10 -1 -testtx1 : 10 -abc -def -id: 1 -name: abc -id: 1 -name: abc -id: 1 -name: abc -********************Tx without opts: Scenario 1******************** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:223.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:23.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: select, and TX1 not commit ---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 commit---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -********************Tx without opts: Scenario 2******************** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:223.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:23.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: update and select, and after TX1 roolback ---------- -f1:1, f2:华为, f3:423.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-176.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 not commit---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 commit---------- -f1:1, f2:华为, f3:423.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-176.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -********************Tx without opts: Scenario 3******************** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:223.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:23.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: update and select, and after TX1 commit ---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 commit and TX2 not commit---------- -f1:1, f2:华为, f3:223.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:23.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 commit and TX2 commit---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -********************Tx with opts: Scenario 1******************** -****ISOLATION LEVEL:Read Uncommitted**** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:223.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:23.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: select, and TX1 not commit ---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 commit---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -****ISOLATION LEVEL:Read Committed**** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:223.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:23.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: select, and TX1 not commit ---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 commit---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -****ISOLATION LEVEL:Repeatable Read**** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:223.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:23.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: select, and TX1 not commit ---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 commit---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -********************Tx with opts: Scenario 2******************** -****ISOLATION LEVEL:Read Uncommitted**** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:223.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:23.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: update and select, and after TX1 roolback ---------- -f1:1, f2:华为, f3:423.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-176.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 not commit---------- -f1:1, f2:华为, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 commit---------- -f1:1, f2:华为, f3:423.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-176.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -****ISOLATION LEVEL:Read Committed**** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: update and select, and after TX1 roolback ---------- -f1:1, f2:华为, f3:723.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-476.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 not commit---------- -f1:1, f2:华为, f3:423.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-176.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 commit---------- -f1:1, f2:华为, f3:723.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-476.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -****ISOLATION LEVEL:Repeatable Read**** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:823.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-576.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: update and select, and after TX1 roolback ---------- -f1:1, f2:华为, f3:1023.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-776.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 not commit---------- -f1:1, f2:华为, f3:723.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-476.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 rollback and TX2 commit---------- -f1:1, f2:华为, f3:1023.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-776.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -********************Tx with opts: Scenario 3******************** -****ISOLATION LEVEL:Read Uncommitted**** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: update and select, and after TX1 commit ---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 commit and TX2 not commit---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 commit and TX2 commit---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -****ISOLATION LEVEL:Read Committed**** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: update and select, and after TX1 commit ---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 commit and TX2 not commit---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 commit and TX2 commit---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -****ISOLATION LEVEL:Repeatable Read**** -----------IN TX1: update and select---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN TX2: update and select, and after TX1 commit ---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 commit and TX2 not commit---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -----------IN DB: select, after TX1 commit and TX2 commit---------- -f1:1, f2:华为, f3:523.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:研究所, f3:-276.7, f4:2022-02-08 10:30:43.31 +0800 CST, f5:false -********************Tx with opts and read only******************** -In a read-only transaction, cannot execute write operation. -current transaction is aborted. -********************Tx without opts and stmt******************** -f1:1, f2:华为, f3:423.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -********************Tx with opts and stmt******************** -f1:1, f2:华为, f3:423.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/Xorm_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/Xorm_test.go.out deleted file mode 100644 index fca315cb6..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/Xorm_test.go.out +++ /dev/null @@ -1,59 +0,0 @@ -column_name: id -column_default: nextval('user_id_seq'::regclass) -is_nullable: NO -data_type: bigint -character_maximum_length: NULL -description: NULL -primarykey: true -uniquekey: false -column_name: name -column_default: NULL -is_nullable: YES -data_type: character varying -character_maximum_length: 255 -description: NULL -primarykey: false -uniquekey: false -column_name: salt -column_default: NULL -is_nullable: YES -data_type: character varying -character_maximum_length: 255 -description: NULL -primarykey: false -uniquekey: false -column_name: age -column_default: NULL -is_nullable: YES -data_type: integer -character_maximum_length: NULL -description: NULL -primarykey: false -uniquekey: false -column_name: passwd -column_default: NULL -is_nullable: YES -data_type: character varying -character_maximum_length: 200 -description: NULL -primarykey: false -uniquekey: false -column_name: created -column_default: NULL -is_nullable: YES -data_type: timestamp without time zone -character_maximum_length: NULL -description: NULL -primarykey: false -uniquekey: false -column_name: updated -column_default: NULL -is_nullable: YES -data_type: timestamp without time zone -character_maximum_length: NULL -description: NULL -primarykey: false -uniquekey: false -indexname: user_pkey -indexdef: CREATE UNIQUE INDEX user_pkey ON "user" USING btree (id) TABLESPACE pg_default -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/bindParam_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/bindParam_test.go.out deleted file mode 100644 index df5b2a83c..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/bindParam_test.go.out +++ /dev/null @@ -1,38 +0,0 @@ -1 -[name id] -1073741821 true -name string -0 0 false -false false -1073741821 true -id string -0 0 false -false false -name: liu -id: 3.34 -[?column? ?column?] -1073741821 true -?column? string -0 0 false -false false -1073741821 true -?column? string -0 0 false -false false -?column?: liu -?column?: 3 -1 -abc 123 -********************Bind With Location******************** -f1:2, f2:hello world, f3:641.43, f4:2022-02-08 10:35:43.000623 +0800 CST, f5:false -f1:3, f2:华为, f3:431.54, f4:2022-02-10 19:11:54.000353 +0800 CST, f5:true -f1:4, f2:北京2022冬奥会, f3:5423.52, f4:2022-02-12 06:11:15.000636 +0800 CST, f5:false -f1:5, f2:nanjing, f3:665537.63, f4:2022-02-14 04:51:22.000748 +0800 CST, f5:true -f1:6, f2:研究所, f3:6503.1, f4:2022-02-16 13:45:55.000675 +0800 CST, f5:true -********************Bind With Name******************** -f1:2, f2:hello world, f3:641.43, f4:2022-02-08 10:35:43.000623 +0800 CST, f5:false -f1:3, f2:华为, f3:431.54, f4:2022-02-10 19:11:54.000353 +0800 CST, f5:true -f1:4, f2:北京2022冬奥会, f3:5423.52, f4:2022-02-12 06:11:15.000636 +0800 CST, f5:false -f1:5, f2:nanjing, f3:665537.63, f4:2022-02-14 04:51:22.000748 +0800 CST, f5:true -f1:6, f2:研究所, f3:6503.1, f4:2022-02-16 13:45:55.000675 +0800 CST, f5:true -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/concurrency_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/concurrency_test.go.out deleted file mode 100644 index 7ef22e9a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/concurrency_test.go.out +++ /dev/null @@ -1 +0,0 @@ -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/conn_parameter_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/conn_parameter_test.go.out deleted file mode 100644 index 66d98ec27..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/conn_parameter_test.go.out +++ /dev/null @@ -1,54 +0,0 @@ -********************No Runtime Parameter******************** -PARSE SUCCESS: connect_timeout=5 -FAILED: connect_timeout=-1, parse error: invalid connect_timeout (negative timeout) -PARSE SUCCESS: connect_timeout=0 -FAILED: connect_timeout=22.33, parse error: invalid syntax) -PARSE SUCCESS: disable_prepared_binary_result=no -PARSE SUCCESS: disable_prepared_binary_result=yes -FAILED: disable_prepared_binary_result=NO, parse error: invalid disable_prepared_binary_result (unrecognized value "NO" for disable_prepared_binary_result) -FAILED: disable_prepared_binary_result=YES, parse error: invalid disable_prepared_binary_result (unrecognized value "YES" for disable_prepared_binary_result) -FAILED: disable_prepared_binary_result=n, parse error: invalid disable_prepared_binary_result (unrecognized value "n" for disable_prepared_binary_result) -FAILED: disable_prepared_binary_result=y, parse error: invalid disable_prepared_binary_result (unrecognized value "y" for disable_prepared_binary_result) -FAILED: disable_prepared_binary_result=N, parse error: invalid disable_prepared_binary_result (unrecognized value "N" for disable_prepared_binary_result) -FAILED: disable_prepared_binary_result=Y, parse error: invalid disable_prepared_binary_result (unrecognized value "Y" for disable_prepared_binary_result) -PARSE SUCCESS: binary_parameters=yes -FAILED: binary_parameters=YES, parse error: invalid binary_parameters (unrecognized value "YES" for binary_parameters) -FAILED: binary_parameters=NO, parse error: invalid binary_parameters (unrecognized value "NO" for binary_parameters) -PARSE SUCCESS: binary_parameters=no -FAILED: binary_parameters=y, parse error: invalid binary_parameters (unrecognized value "y" for binary_parameters) -FAILED: binary_parameters=Y, parse error: invalid binary_parameters (unrecognized value "Y" for binary_parameters) -FAILED: binary_parameters=n, parse error: invalid binary_parameters (unrecognized value "n" for binary_parameters) -FAILED: binary_parameters=N, parse error: invalid binary_parameters (unrecognized value "N" for binary_parameters) -********************Runtime Parameter******************** -RESULT: show application_name: go-test-api -RESULT: show application_name: default -RESULT: show application_name: 123456 -RESULT: show datestyle: SQL, YMD -RESULT: show datestyle: ISO, MDY -FAILED: datestyle=SQL, YMD, parse error: failed to parse as DSN (invalid dsn) -RESULT: show timezone: GMT -FAILED: timezone=ABC, parse error: bad connection -RESULT: show timezone: 08:00:00 -RESULT: show timezone: -05:00 -RESULT: show timezone: 22:00:00 -RESULT: show timezone: 24:00:00 -RESULT: show timezone: -23:00:00 -RESULT: show timezone: 25:00:00 -RESULT: show timezone: -24:00:00 -RESULT: show timezone: 1234:00:00 -RESULT: show client_encoding: SQL_ASCII -RESULT: show client_encoding: GBK -RESULT: show client_encoding: UTF8 -FAILED: client_encoding=ABCD, parse error: bad connection -FAILED: client_encoding=default, parse error: bad connection -FAILED: client_encoding=0, parse error: bad connection -RESULT: show search_path: pqgotest -RESULT: show search_path: 12345 -RESULT: show search_path: default -RESULT: show extra_float_digits: 0 -RESULT: show extra_float_digits: -15 -RESULT: show extra_float_digits: 3 -FAILED: extra_float_digits=4, parse error: bad connection -FAILED: extra_float_digits=-16, parse error: bad connection -FAILED: extra_float_digits=3.4, parse error: bad connection -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/datatype_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/datatype_test.go.out deleted file mode 100644 index c6040565f..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/datatype_test.go.out +++ /dev/null @@ -1,411 +0,0 @@ -a: 1 -b: abc -d: 1.2340000000 -e: 127 -f: false -g: 123456 -k: ["2010-01-01 14:30:00","2010-01-01 15:30:00"] -a: 2 -b: abc -d: 1.2340000000 -e: 127 -f: true -g: 223456 -k: ["2010-01-01 14:30:00","2010-01-01 15:30:00"] -********************Integer Datatype******************** -----------result is golang string---------- -F1:255, F2:32767, F3:2147483647, F4:2147483647, F5:9223372036854775807, F6:123 -F1:0, F2:0, F3:0, F4:0, F5:0, F6:123 -F1:0, F2:-32768, F3:-2147483648, F4:-2147483648, F5:-9223372036854775808, F6:123 - -----------result is golang interface{}---------- -F1:[50 53 53], F2:32767, F3:2147483647, F4:2147483647, F5:9223372036854775807, F6:123 -F1:[48], F2:0, F3:0, F4:0, F5:0, F6:123 -F1:[48], F2:-32768, F3:-2147483648, F4:-2147483648, F5:-9223372036854775808, F6:123 - -----------result is golang []byte---------- -F1:[50 53 53], F2:[51 50 55 54 55], F3:[50 49 52 55 52 56 51 54 52 55], F4:[50 49 52 55 52 56 51 54 52 55], F5:[57 50 50 51 51 55 50 48 51 54 56 53 52 55 55 53 56 48 55], F6:[49 50 51] -F1:[48], F2:[48], F3:[48], F4:[48], F5:[48], F6:[49 50 51] -F1:[48], F2:[45 51 50 55 54 56], F3:[45 50 49 52 55 52 56 51 54 52 56], F4:[45 50 49 52 55 52 56 51 54 52 56], F5:[45 57 50 50 51 51 55 50 48 51 54 56 53 52 55 55 53 56 48 56], F6:[49 50 51] - -----------result is golang sql.RawBytes---------- -F1:[50 53 53], F2:[51 50 55 54 55], F3:[50 49 52 55 52 56 51 54 52 55], F4:[50 49 52 55 52 56 51 54 52 55], F5:[57 50 50 51 51 55 50 48 51 54 56 53 52 55 55 53 56 48 55], F6:[49 50 51] -F1:[48], F2:[48], F3:[48], F4:[48], F5:[48], F6:[49 50 51] -F1:[48], F2:[45 51 50 55 54 56], F3:[45 50 49 52 55 52 56 51 54 52 56], F4:[45 50 49 52 55 52 56 51 54 52 56], F5:[45 57 50 50 51 51 55 50 48 51 54 56 53 52 55 55 53 56 48 56], F6:[49 50 51] - -----------result is golang bool---------- -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert "255" into type bool -sql: Scan error on column index 5, name "i1toi2": sql/driver: couldn't convert 123 into type bool -sql: Scan error on column index 1, name "f2": sql/driver: couldn't convert -32768 into type bool - -----------result is golang integer---------- -F1:255, F2:32767, F3:2147483647, F4:2147483647, F5:9223372036854775807, F6:123 -F1:0, F2:0, F3:0, F4:0, F5:0, F6:123 -F1:0, F2:-32768, F3:-2147483648, F4:-2147483648, F5:-9223372036854775808, F6:123 - -----------result is golang float---------- -F1:255, F2:32767, F3:2.147483647e+09, F4:2.147483647e+09, F5:9.223372036854776e+18, F6:123 -F1:0, F2:0, F3:0, F4:0, F5:0, F6:123 -F1:0, F2:-32768, F3:-2.147483648e+09, F4:-2.147483648e+09, F5:-9.223372036854776e+18, F6:123 - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time - -********************Numeric Datatype******************** -----------result is golang string---------- -F1:437164.41907403710, F2:71.6149, F3:34819647147, F4:437164.41907403710, F5:71.6149, F6:34819647147 - -----------result is golang interface{}---------- -F1:[52 51 55 49 54 52 46 52 49 57 48 55 52 48 51 55 49 48], F2:[55 49 46 54 49 52 57], F3:[51 52 56 49 57 54 52 55 49 52 55], F4:[52 51 55 49 54 52 46 52 49 57 48 55 52 48 51 55 49 48], F5:[55 49 46 54 49 52 57], F6:[51 52 56 49 57 54 52 55 49 52 55] - -----------result is golang []byte---------- -F1:[52 51 55 49 54 52 46 52 49 57 48 55 52 48 51 55 49 48], F2:[55 49 46 54 49 52 57], F3:[51 52 56 49 57 54 52 55 49 52 55], F4:[52 51 55 49 54 52 46 52 49 57 48 55 52 48 51 55 49 48], F5:[55 49 46 54 49 52 57], F6:[51 52 56 49 57 54 52 55 49 52 55] - -----------result is golang sql.RawBytes---------- -F1:[52 51 55 49 54 52 46 52 49 57 48 55 52 48 51 55 49 48], F2:[55 49 46 54 49 52 57], F3:[51 52 56 49 57 54 52 55 49 52 55], F4:[52 51 55 49 54 52 46 52 49 57 48 55 52 48 51 55 49 48], F5:[55 49 46 54 49 52 57], F6:[51 52 56 49 57 54 52 55 49 52 55] - -----------result is golang bool---------- -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert "437164.41907403710" into type bool - -----------result is golang integer---------- -sql: Scan error on column index 0, name "f1": converting driver.Value type []uint8 ("437164.41907403710") to a int64: invalid syntax - -----------result is golang float---------- -F1:437164.4190740371, F2:71.6149, F3:3.4819647147e+10, F4:437164.4190740371, F5:71.6149, F6:3.4819647147e+10 - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time - -********************Float Datatype******************** -----------result is golang string---------- -F1:4164.52, F2:34847.0438321, F3:437164.41940371, F4:71.6149329, F5:71.6933, F6:34819647147.04 - -----------result is golang interface{}---------- -F1:4164.52, F2:34847.0438321, F3:437164.41940371, F4:71.6149329, F5:[55 49 46 54 57 51 51], F6:[51 52 56 49 57 54 52 55 49 52 55 46 48 52] - -----------result is golang []byte---------- -F1:[52 49 54 52 46 53 50], F2:[51 52 56 52 55 46 48 52 51 56 51 50 49], F3:[52 51 55 49 54 52 46 52 49 57 52 48 51 55 49], F4:[55 49 46 54 49 52 57 51 50 57], F5:[55 49 46 54 57 51 51], F6:[51 52 56 49 57 54 52 55 49 52 55 46 48 52] - -----------result is golang sql.RawBytes---------- -F1:[52 49 54 52 46 53 50], F2:[51 52 56 52 55 46 48 52 51 56 51 50 49], F3:[52 51 55 49 54 52 46 52 49 57 52 48 51 55 49], F4:[55 49 46 54 49 52 57 51 50 57], F5:[55 49 46 54 57 51 51], F6:[51 52 56 49 57 54 52 55 49 52 55 46 48 52] - -----------result is golang bool---------- -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert 4164.52 (float64) into type bool - -----------result is golang integer---------- -sql: Scan error on column index 0, name "f1": converting driver.Value type float64 ("4164.52") to a int64: invalid syntax - -----------result is golang float---------- -F1:4164.52, F2:34847.0438321, F3:437164.41940371, F4:71.6149329, F5:71.6933, F6:3.481964714704e+10 - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type float64 into type *time.Time - -********************Serial Datatype******************** -----------result is golang string---------- -F1:1, F2:1, F3:1, F4:1, F5:1, F6:1 - -----------result is golang interface{}---------- -F1:1, F2:1, F3:1, F4:1, F5:1, F6:1 - -----------result is golang []byte---------- -F1:[49], F2:[49], F3:[49], F4:[49], F5:[49], F6:[49] - -----------result is golang sql.RawBytes---------- -F1:[49], F2:[49], F3:[49], F4:[49], F5:[49], F6:[49] - -----------result is golang bool---------- -F1:true, F2:true, F3:true, F4:true, F5:true, F6:true - -----------result is golang integer---------- -F1:1, F2:1, F3:1, F4:1, F5:1, F6:1 - -----------result is golang float---------- -F1:1, F2:1, F3:1, F4:1, F5:1, F6:1 - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type int64 into type *time.Time -********************Datetime Datatype******************** -----------result is golang string---------- -F1:2022-01-28T00:00:00Z, F2:0000-01-01T14:56:38.687146Z, F3:0000-01-01T14:56:38.687146Z, F4:2022-01-28T14:56:38.687146Z, F5:2022-01-28T23:01:28.382264+08:00 - -----------result is golang interface{}---------- -F1:2022-01-28 00:00:00 +0000 +0000, F2:0000-01-01 14:56:38.687146 +0000 UTC, F3:0000-01-01 14:56:38.687146 +0000 +0000, F4:2022-01-28 14:56:38.687146 +0000 +0000, F5:2022-01-28 23:01:28.382264 +0800 CST - -----------result is golang []byte---------- -F1:[50 48 50 50 45 48 49 45 50 56 84 48 48 58 48 48 58 48 48 90], F2:[48 48 48 48 45 48 49 45 48 49 84 49 52 58 53 54 58 51 56 46 54 56 55 49 52 54 90], F3:[48 48 48 48 45 48 49 45 48 49 84 49 52 58 53 54 58 51 56 46 54 56 55 49 52 54 90], F4:[50 48 50 50 45 48 49 45 50 56 84 49 52 58 53 54 58 51 56 46 54 56 55 49 52 54 90], F5:[50 48 50 50 45 48 49 45 50 56 84 50 51 58 48 49 58 50 56 46 51 56 50 50 54 52 43 48 56 58 48 48] - -----------result is golang sql.RawBytes---------- -F1:[50 48 50 50 45 48 49 45 50 56 84 48 48 58 48 48 58 48 48 90], F2:[48 48 48 48 45 48 49 45 48 49 84 49 52 58 53 54 58 51 56 46 54 56 55 49 52 54 90], F3:[48 48 48 48 45 48 49 45 48 49 84 49 52 58 53 54 58 51 56 46 54 56 55 49 52 54 90], F4:[50 48 50 50 45 48 49 45 50 56 84 49 52 58 53 54 58 51 56 46 54 56 55 49 52 54 90], F5:[50 48 50 50 45 48 49 45 50 56 84 50 51 58 48 49 58 50 56 46 51 56 50 50 54 52 43 48 56 58 48 48] - -----------result is golang time.Time---------- -F1:2022-01-28 00:00:00 +0000 +0000, F2:0000-01-01 14:56:38.687146 +0000 UTC, F3:0000-01-01 14:56:38.687146 +0000 +0000, F4:2022-01-28 14:56:38.687146 +0000 +0000, F5:2022-01-28 23:01:28.382264 +0800 CST - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": converting driver.Value type time.Time ("2022-01-28 00:00:00 +0000 +0000") to a int64: invalid syntax - -********************Interval Datatype******************** -----------result is golang string---------- -F1:2022-01-28 15:01:00, F2:3 days, F3:2 years, F4:-19 years -4 mons -04:04:00, F5:2022-01-28 23:00:00+08 - -----------result is golang interface{}---------- -F1:[50 48 50 50 45 48 49 45 50 56 32 49 53 58 48 49 58 48 48], F2:[51 32 100 97 121 115], F3:[50 32 121 101 97 114 115], F4:[45 49 57 32 121 101 97 114 115 32 45 52 32 109 111 110 115 32 45 48 52 58 48 52 58 48 48], F5:[50 48 50 50 45 48 49 45 50 56 32 50 51 58 48 48 58 48 48 43 48 56] - -----------result is golang []byte---------- -F1:[50 48 50 50 45 48 49 45 50 56 32 49 53 58 48 49 58 48 48], F2:[51 32 100 97 121 115], F3:[50 32 121 101 97 114 115], F4:[45 49 57 32 121 101 97 114 115 32 45 52 32 109 111 110 115 32 45 48 52 58 48 52 58 48 48], F5:[50 48 50 50 45 48 49 45 50 56 32 50 51 58 48 48 58 48 48 43 48 56] - -----------result is golang sql.RawBytes---------- -F1:[50 48 50 50 45 48 49 45 50 56 32 49 53 58 48 49 58 48 48], F2:[51 32 100 97 121 115], F3:[50 32 121 101 97 114 115], F4:[45 49 57 32 121 101 97 114 115 32 45 52 32 109 111 110 115 32 45 48 52 58 48 52 58 48 48], F5:[50 48 50 50 45 48 49 45 50 56 32 50 51 58 48 48 58 48 48 43 48 56] - -----------result is golang time.Time---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": converting driver.Value type []uint8 ("2022-01-28 15:01:00") to a int64: invalid syntax -********************Money Datatype******************** -----------result is golang string---------- -F1:$100.00 -F1:$2,090.11 -F1:$12.43 - -----------result is golang interface{}---------- -F1:[36 49 48 48 46 48 48] -F1:[36 50 44 48 57 48 46 49 49] -F1:[36 49 50 46 52 51] - -----------result is golang []byte---------- -F1:[36 49 48 48 46 48 48] -F1:[36 50 44 48 57 48 46 49 49] -F1:[36 49 50 46 52 51] - -----------result is golang sql.RawBytes---------- -F1:[36 49 48 48 46 48 48] -F1:[36 50 44 48 57 48 46 49 49] -F1:[36 49 50 46 52 51] - -----------result is golang bool---------- -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert "$100.00" into type bool -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert "$2,090.11" into type bool -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert "$12.43" into type bool - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": converting driver.Value type []uint8 ("$100.00") to a int64: invalid syntax -sql: Scan error on column index 0, name "f1": converting driver.Value type []uint8 ("$2,090.11") to a int64: invalid syntax -sql: Scan error on column index 0, name "f1": converting driver.Value type []uint8 ("$12.43") to a int64: invalid syntax - -********************Bool Datatype******************** -----------result is golang string---------- -F1:true -F1:false -F1:true - -----------result is golang interface{}---------- -F1:true -F1:false -F1:true - -----------result is golang []byte---------- -F1:[116 114 117 101] -F1:[102 97 108 115 101] -F1:[116 114 117 101] - -----------result is golang sql.RawBytes---------- -F1:[116 114 117 101] -F1:[102 97 108 115 101] -F1:[116 114 117 101] - -----------result is golang bool---------- -F1:true -F1:false -F1:true - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": converting driver.Value type bool ("true") to a int64: invalid syntax -sql: Scan error on column index 0, name "f1": converting driver.Value type bool ("false") to a int64: invalid syntax -sql: Scan error on column index 0, name "f1": converting driver.Value type bool ("true") to a int64: invalid syntax -********************Character Datatype******************** -----------result is golang string---------- -F1:a, F2:你 , F3:bbb, F4:2090.11, F5:中国, F6:dgjqgdgfakgfekikgqif, F7:dgjqgdgfakgfekikgqif -F1:1, F2:true, F3:0, F4:false, F5:f, F6:TRUE, F7:FALSE -F1:1, F2:2000, F3:0, F4:4, F5:5, F6:6, F7:7 - -----------result is golang interface{}---------- -F1:[97], F2:[228 189 160 32], F3:bbb, F4:2090.11, F5:[228 184 173 229 155 189], F6:dgjqgdgfakgfekikgqif, F7:[100 103 106 113 103 100 103 102 97 107 103 102 101 107 105 107 103 113 105 102] -F1:[49], F2:[116 114 117 101], F3:0, F4:false, F5:[102], F6:TRUE, F7:[70 65 76 83 69] -F1:[49], F2:[50 48 48 48], F3:0, F4:4, F5:[53], F6:6, F7:[55] - -----------result is golang []byte---------- -F1:[97], F2:[228 189 160 32], F3:[98 98 98], F4:[50 48 57 48 46 49 49], F5:[228 184 173 229 155 189], F6:[100 103 106 113 103 100 103 102 97 107 103 102 101 107 105 107 103 113 105 102], F7:[100 103 106 113 103 100 103 102 97 107 103 102 101 107 105 107 103 113 105 102] -F1:[49], F2:[116 114 117 101], F3:[48], F4:[102 97 108 115 101], F5:[102], F6:[84 82 85 69], F7:[70 65 76 83 69] -F1:[49], F2:[50 48 48 48], F3:[48], F4:[52], F5:[53], F6:[54], F7:[55] - -----------result is golang sql.RawBytes---------- -F1:[97], F2:[228 189 160 32], F3:[98 98 98], F4:[50 48 57 48 46 49 49], F5:[228 184 173 229 155 189], F6:[100 103 106 113 103 100 103 102 97 107 103 102 101 107 105 107 103 113 105 102], F7:[100 103 106 113 103 100 103 102 97 107 103 102 101 107 105 107 103 113 105 102] -F1:[49], F2:[116 114 117 101], F3:[48], F4:[102 97 108 115 101], F5:[102], F6:[84 82 85 69], F7:[70 65 76 83 69] -F1:[49], F2:[50 48 48 48], F3:[48], F4:[52], F5:[53], F6:[54], F7:[55] - -----------result is golang bool---------- -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert "a" into type bool -F1:true, F2:true, F3:false, F4:false, F5:false, F6:true, F7:false -sql: Scan error on column index 1, name "f2": sql/driver: couldn't convert "2000" into type bool - -----------result is golang integer---------- -sql: Scan error on column index 0, name "f1": converting driver.Value type []uint8 ("a") to a int64: invalid syntax -sql: Scan error on column index 1, name "f2": converting driver.Value type []uint8 ("true") to a int64: invalid syntax -F1:1, F2:2000, F3:0, F4:4, F5:5, F6:6, F7:7 - -----------result is golang float---------- -sql: Scan error on column index 0, name "f1": converting driver.Value type []uint8 ("a") to a float64: invalid syntax -sql: Scan error on column index 1, name "f2": converting driver.Value type []uint8 ("true") to a float64: invalid syntax -F1:1, F2:2000, F3:0, F4:4, F5:5, F6:6, F7:7 - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time - -********************Binary Datatype******************** -----------result is golang string---------- -F1:0123, F2:0ABC, F3:deqde, F4:0123, F5:0ABC, F6:deqde, F7:0123 - -----------result is golang interface{}---------- -F1:[48 49 50 51], F2:[48 65 66 67], F3:[100 101 113 100 101], F4:[48 49 50 51], F5:[48 65 66 67], F6:[100 101 113 100 101], F7:[48 49 50 51] - -----------result is golang []byte---------- -F1:[48 49 50 51], F2:[48 65 66 67], F3:[100 101 113 100 101], F4:[48 49 50 51], F5:[48 65 66 67], F6:[100 101 113 100 101], F7:[48 49 50 51] - -----------result is golang sql.RawBytes---------- -F1:[48 49 50 51], F2:[48 65 66 67], F3:[100 101 113 100 101], F4:[48 49 50 51], F5:[48 65 66 67], F6:[100 101 113 100 101], F7:[48 49 50 51] - -----------result is golang bool---------- -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert "0123" into type bool - -----------result is golang integer---------- -sql: Scan error on column index 1, name "f2": converting driver.Value type []uint8 ("0ABC") to a int64: invalid syntax - -----------result is golang float---------- -sql: Scan error on column index 1, name "f2": converting driver.Value type []uint8 ("0ABC") to a float64: invalid syntax - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time -********************Geometry Datatype******************** -----------result is golang string---------- -F1:(1,2), F2:[(1,2),(3,4)], F3:(2,2),(1,1), F4:((1,0),(2,0),(3,4)), F5:((1,0),(2,0),(3,4)), F6:<(0,0),2> - -----------result is golang interface{}---------- -F1:[40 49 44 50 41], F2:[91 40 49 44 50 41 44 40 51 44 52 41 93], F3:[40 50 44 50 41 44 40 49 44 49 41], F4:[40 40 49 44 48 41 44 40 50 44 48 41 44 40 51 44 52 41 41], F5:[40 40 49 44 48 41 44 40 50 44 48 41 44 40 51 44 52 41 41], F6:[60 40 48 44 48 41 44 50 62] - -----------result is golang []byte---------- -F1:[40 49 44 50 41], F2:[91 40 49 44 50 41 44 40 51 44 52 41 93], F3:[40 50 44 50 41 44 40 49 44 49 41], F4:[40 40 49 44 48 41 44 40 50 44 48 41 44 40 51 44 52 41 41], F5:[40 40 49 44 48 41 44 40 50 44 48 41 44 40 51 44 52 41 41], F6:[60 40 48 44 48 41 44 50 62] - -----------result is golang sql.RawBytes---------- -F1:[40 49 44 50 41], F2:[91 40 49 44 50 41 44 40 51 44 52 41 93], F3:[40 50 44 50 41 44 40 49 44 49 41], F4:[40 40 49 44 48 41 44 40 50 44 48 41 44 40 51 44 52 41 41], F5:[40 40 49 44 48 41 44 40 50 44 48 41 44 40 51 44 52 41 41], F6:[60 40 48 44 48 41 44 50 62] - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time -********************NetAddr Datatype******************** -----------result is golang string---------- -F1:192.168.0.0/24, F2:192.168.1.5/8, F3:08:00:2b:01:02:03 -F1:192.1.0.0/24, F2:192.1.2.1, F3:08:00:2b:01:02:03 - -----------result is golang interface{}---------- -F1:[49 57 50 46 49 54 56 46 48 46 48 47 50 52], F2:[49 57 50 46 49 54 56 46 49 46 53 47 56], F3:[48 56 58 48 48 58 50 98 58 48 49 58 48 50 58 48 51] -F1:[49 57 50 46 49 46 48 46 48 47 50 52], F2:[49 57 50 46 49 46 50 46 49], F3:[48 56 58 48 48 58 50 98 58 48 49 58 48 50 58 48 51] - -----------result is golang []byte---------- -F1:[49 57 50 46 49 54 56 46 48 46 48 47 50 52], F2:[49 57 50 46 49 54 56 46 49 46 53 47 56], F3:[48 56 58 48 48 58 50 98 58 48 49 58 48 50 58 48 51] -F1:[49 57 50 46 49 46 48 46 48 47 50 52], F2:[49 57 50 46 49 46 50 46 49], F3:[48 56 58 48 48 58 50 98 58 48 49 58 48 50 58 48 51] - -----------result is golang sql.RawBytes---------- -F1:[49 57 50 46 49 54 56 46 48 46 48 47 50 52], F2:[49 57 50 46 49 54 56 46 49 46 53 47 56], F3:[48 56 58 48 48 58 50 98 58 48 49 58 48 50 58 48 51] -F1:[49 57 50 46 49 46 48 46 48 47 50 52], F2:[49 57 50 46 49 46 50 46 49], F3:[48 56 58 48 48 58 50 98 58 48 49 58 48 50 58 48 51] - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type []uint8 into type *time.Time - -********************BitStr Datatype******************** -----------result is golang string---------- -F1:1, F2:101, F3:1011 -F1:2, F2:100, F3:01 - -----------result is golang interface{}---------- -F1:1, F2:[49 48 49], F3:[49 48 49 49] -F1:2, F2:[49 48 48], F3:[48 49] - -----------result is golang []byte---------- -F1:[49], F2:[49 48 49], F3:[49 48 49 49] -F1:[50], F2:[49 48 48], F3:[48 49] - -----------result is golang sql.RawBytes---------- -F1:[49], F2:[49 48 49], F3:[49 48 49 49] -F1:[50], F2:[49 48 48], F3:[48 49] - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type int64 into type *time.Time -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type int64 into type *time.Time - -********************TextSearch Datatype******************** -----------result is golang string---------- -F1:1, F2:'a' 'and' 'ate' 'cat' 'fat' 'mat' 'on' 'rat' 'sat', F3:'fat' & 'rat' - -----------result is golang interface{}---------- -F1:1, F2:[39 97 39 32 39 97 110 100 39 32 39 97 116 101 39 32 39 99 97 116 39 32 39 102 97 116 39 32 39 109 97 116 39 32 39 111 110 39 32 39 114 97 116 39 32 39 115 97 116 39], F3:[39 102 97 116 39 32 38 32 39 114 97 116 39] - -----------result is golang []byte---------- -F1:[49], F2:[39 97 39 32 39 97 110 100 39 32 39 97 116 101 39 32 39 99 97 116 39 32 39 102 97 116 39 32 39 109 97 116 39 32 39 111 110 39 32 39 114 97 116 39 32 39 115 97 116 39], F3:[39 102 97 116 39 32 38 32 39 114 97 116 39] - -----------result is golang sql.RawBytes---------- -F1:[49], F2:[39 97 39 32 39 97 110 100 39 32 39 97 116 101 39 32 39 99 97 116 39 32 39 102 97 116 39 32 39 109 97 116 39 32 39 111 110 39 32 39 114 97 116 39 32 39 115 97 116 39], F3:[39 102 97 116 39 32 38 32 39 114 97 116 39] - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": unsupported Scan, storing driver.Value type int64 into type *time.Time -********************Range Datatype******************** -----------result is golang string---------- -F1:[-1,11), F2:[-2910,7738), F3:(367.431,731.431], F4:("2010-01-01 14:30:00","2010-01-04 15:30:00"), F5:["2022-01-28 23:01:28.382264+08","2022-01-30 23:01:28.382264+08"], F6:[2022-01-28,2022-02-01) - -----------result is golang interface{}---------- -F1:[91 45 49 44 49 49 41], F2:[91 45 50 57 49 48 44 55 55 51 56 41], F3:[40 51 54 55 46 52 51 49 44 55 51 49 46 52 51 49 93], F4:[40 34 50 48 49 48 45 48 49 45 48 49 32 49 52 58 51 48 58 48 48 34 44 34 50 48 49 48 45 48 49 45 48 52 32 49 53 58 51 48 58 48 48 34 41], F5:[91 34 50 48 50 50 45 48 49 45 50 56 32 50 51 58 48 49 58 50 56 46 51 56 50 50 54 52 43 48 56 34 44 34 50 48 50 50 45 48 49 45 51 48 32 50 51 58 48 49 58 50 56 46 51 56 50 50 54 52 43 48 56 34 93], F6:[91 50 48 50 50 45 48 49 45 50 56 44 50 48 50 50 45 48 50 45 48 49 41] - -----------result is golang []byte---------- -F1:[91 45 49 44 49 49 41], F2:[91 45 50 57 49 48 44 55 55 51 56 41], F3:[40 51 54 55 46 52 51 49 44 55 51 49 46 52 51 49 93], F4:[40 34 50 48 49 48 45 48 49 45 48 49 32 49 52 58 51 48 58 48 48 34 44 34 50 48 49 48 45 48 49 45 48 52 32 49 53 58 51 48 58 48 48 34 41], F5:[91 34 50 48 50 50 45 48 49 45 50 56 32 50 51 58 48 49 58 50 56 46 51 56 50 50 54 52 43 48 56 34 44 34 50 48 50 50 45 48 49 45 51 48 32 50 51 58 48 49 58 50 56 46 51 56 50 50 54 52 43 48 56 34 93], F6:[91 50 48 50 50 45 48 49 45 50 56 44 50 48 50 50 45 48 50 45 48 49 41] - -----------result is golang sql.RawBytes---------- -F1:[91 45 49 44 49 49 41], F2:[91 45 50 57 49 48 44 55 55 51 56 41], F3:[40 51 54 55 46 52 51 49 44 55 51 49 46 52 51 49 93], F4:[40 34 50 48 49 48 45 48 49 45 48 49 32 49 52 58 51 48 58 48 48 34 44 34 50 48 49 48 45 48 49 45 48 52 32 49 53 58 51 48 58 48 48 34 41], F5:[91 34 50 48 50 50 45 48 49 45 50 56 32 50 51 58 48 49 58 50 56 46 51 56 50 50 54 52 43 48 56 34 44 34 50 48 50 50 45 48 49 45 51 48 32 50 51 58 48 49 58 50 56 46 51 56 50 50 54 52 43 48 56 34 93], F6:[91 50 48 50 50 45 48 49 45 50 56 44 50 48 50 50 45 48 50 45 48 49 41] - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert "[-1,11)" into type bool - -********************Json Datatype******************** -----------result is golang string---------- -F1: [1, " a ", {"a" :1 }] , F2:[1, " a ", {"a": 1}], F3:{"a" : 1, "a" : 2}, F4:{"a": 2}, F5:{"aa" : 1, "b" : 2, "a" : 3}, F6:{"a": 3, "b": 2, "aa": 1} - -----------result is golang interface{}---------- -F1:[32 32 32 91 49 44 32 34 32 97 32 34 44 32 123 34 97 34 32 32 32 58 49 32 32 32 32 125 93 32 32], F2:[91 49 44 32 34 32 97 32 34 44 32 123 34 97 34 58 32 49 125 93], F3:[123 34 97 34 32 58 32 49 44 32 34 97 34 32 58 32 50 125], F4:[123 34 97 34 58 32 50 125], F5:[123 34 97 97 34 32 58 32 49 44 32 34 98 34 32 58 32 50 44 32 34 97 34 32 58 32 51 125], F6:[123 34 97 34 58 32 51 44 32 34 98 34 58 32 50 44 32 34 97 97 34 58 32 49 125] - -----------result is golang []byte---------- -F1:[32 32 32 91 49 44 32 34 32 97 32 34 44 32 123 34 97 34 32 32 32 58 49 32 32 32 32 125 93 32 32], F2:[91 49 44 32 34 32 97 32 34 44 32 123 34 97 34 58 32 49 125 93], F3:[123 34 97 34 32 58 32 49 44 32 34 97 34 32 58 32 50 125], F4:[123 34 97 34 58 32 50 125], F5:[123 34 97 97 34 32 58 32 49 44 32 34 98 34 32 58 32 50 44 32 34 97 34 32 58 32 51 125], F6:[123 34 97 34 58 32 51 44 32 34 98 34 58 32 50 44 32 34 97 97 34 58 32 49 125] - -----------result is golang sql.RawBytes---------- -F1:[32 32 32 91 49 44 32 34 32 97 32 34 44 32 123 34 97 34 32 32 32 58 49 32 32 32 32 125 93 32 32], F2:[91 49 44 32 34 32 97 32 34 44 32 123 34 97 34 58 32 49 125 93], F3:[123 34 97 34 32 58 32 49 44 32 34 97 34 32 58 32 50 125], F4:[123 34 97 34 58 32 50 125], F5:[123 34 97 97 34 32 58 32 49 44 32 34 98 34 32 58 32 50 44 32 34 97 34 32 58 32 51 125], F6:[123 34 97 34 58 32 51 44 32 34 98 34 58 32 50 44 32 34 97 97 34 58 32 49 125] - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert " [1, \" a \", {\"a\" :1 }] " into type bool -********************Other Datatype******************** -----------result is golang string---------- -F1:a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11, F2:e697da2eaa3a775b, F3:685847ed1fe38e18f6b0e2b18c00edee, F4:\x484c4c00000000002b05000000000000000000000000000000000000 - -----------result is golang interface{}---------- -F1:[97 48 101 101 98 99 57 57 45 57 99 48 98 45 52 101 102 56 45 98 98 54 100 45 54 98 98 57 98 100 51 56 48 97 49 49], F2:[101 54 57 55 100 97 50 101 97 97 51 97 55 55 53 98], F3:[54 56 53 56 52 55 101 100 49 102 101 51 56 101 49 56 102 54 98 48 101 50 98 49 56 99 48 48 101 100 101 101], F4:[92 120 52 56 52 99 52 99 48 48 48 48 48 48 48 48 48 48 50 98 48 53 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48] - -----------result is golang []byte---------- -F1:[97 48 101 101 98 99 57 57 45 57 99 48 98 45 52 101 102 56 45 98 98 54 100 45 54 98 98 57 98 100 51 56 48 97 49 49], F2:[101 54 57 55 100 97 50 101 97 97 51 97 55 55 53 98], F3:[54 56 53 56 52 55 101 100 49 102 101 51 56 101 49 56 102 54 98 48 101 50 98 49 56 99 48 48 101 100 101 101], F4:[92 120 52 56 52 99 52 99 48 48 48 48 48 48 48 48 48 48 50 98 48 53 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48] - -----------result is golang sql.RawBytes---------- -F1:[97 48 101 101 98 99 57 57 45 57 99 48 98 45 52 101 102 56 45 98 98 54 100 45 54 98 98 57 98 100 51 56 48 97 49 49], F2:[101 54 57 55 100 97 50 101 97 97 51 97 55 55 53 98], F3:[54 56 53 56 52 55 101 100 49 102 101 51 56 101 49 56 102 54 98 48 101 50 98 49 56 99 48 48 101 100 101 101], F4:[92 120 52 56 52 99 52 99 48 48 48 48 48 48 48 48 48 48 50 98 48 53 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48 48] - -----------result is golang others---------- -sql: Scan error on column index 0, name "f1": sql/driver: couldn't convert "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11" into type bool -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/db_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/db_test.go.out deleted file mode 100644 index 213d16e24..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/db_test.go.out +++ /dev/null @@ -1,15 +0,0 @@ -********************DB Exec******************** -f1:1, f2:abcdefg, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:hello world, f3:641.43, f4:2022-02-08 10:35:43.000623 +0800 CST, f5:false -f1:3, f2:华为, f3:431.54, f4:2022-02-10 19:11:54.000353 +0800 CST, f5:true -f1:4, f2:北京2022冬奥会, f3:5423.52, f4:2022-02-12 06:11:15.000636 +0800 CST, f5:false -f1:5, f2:nanjing, f3:665537.63, f4:2022-02-14 04:51:22.000748 +0800 CST, f5:true -f1:6, f2:研究所, f3:6503.1, f4:2022-02-16 13:45:55.000675 +0800 CST, f5:true -********************DB ExecContext******************** -f1:1, f2:abcdefg, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:hello world, f3:641.43, f4:2022-02-08 10:35:43.000623 +0800 CST, f5:false -f1:3, f2:华为, f3:431.54, f4:2022-02-10 19:11:54.000353 +0800 CST, f5:true -f1:4, f2:北京2022冬奥会, f3:5423.52, f4:2022-02-12 06:11:15.000636 +0800 CST, f5:false -f1:5, f2:nanjing, f3:665537.63, f4:2022-02-14 04:51:22.000748 +0800 CST, f5:true -f1:6, f2:研究所, f3:6503.1, f4:2022-02-16 13:45:55.000675 +0800 CST, f5:true -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/ping_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/ping_test.go.out deleted file mode 100644 index e47d180b1..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/ping_test.go.out +++ /dev/null @@ -1,4 +0,0 @@ -name: abc -id: 1 -name: abc -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/row_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/row_test.go.out deleted file mode 100644 index 4602c3636..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/row_test.go.out +++ /dev/null @@ -1,20 +0,0 @@ -********************Query with Row******************** -f1:1, f2:abcdefg, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -The name of columns is f1 f2 f3 f4 f5 -********************Query with Rows******************** -f1:2, f2:hello world, f3:641.43, f4:2022-02-08 10:35:43.000623 +0800 CST, f5:false -f1:3, f2:华为, f3:431.54, f4:2022-02-10 19:11:54.000353 +0800 CST, f5:true -f1:4, f2:北京2022冬奥会, f3:5423.52, f4:2022-02-12 06:11:15.000636 +0800 CST, f5:false -f1:5, f2:nanjing, f3:665537.63, f4:2022-02-14 04:51:22.000748 +0800 CST, f5:true -f1:6, f2:研究所, f3:6503.1, f4:2022-02-16 13:45:55.000675 +0800 CST, f5:true -********************Get ColumnType******************** -Name is f1, DatabaseTypeName is INT4. ScanType is int32. -Name is f2, DatabaseTypeName is VARCHAR. Sting length is 20. ScanType is string. -Name is f3, DatabaseTypeName is NUMERIC. Decimal precision is 20, scale is 4. ScanType is interface {}. -Name is f4, DatabaseTypeName is TIMESTAMPTZ. ScanType is time.Time. -Name is f5, DatabaseTypeName is BOOL. ScanType is bool. -Name is f6, DatabaseTypeName is FLOAT8. ScanType is float64. -Name is f7, DatabaseTypeName is MONEY. ScanType is interface {}. -Name is f8, DatabaseTypeName is POLYGON. ScanType is interface {}. -Name is f9, DatabaseTypeName is BYTEA. Sting length is 1073733621. ScanType is []uint8. -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/ssl_conn_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/ssl_conn_test.go.out deleted file mode 100644 index 7ef22e9a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/ssl_conn_test.go.out +++ /dev/null @@ -1 +0,0 @@ -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/stmt_test.go.out b/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/stmt_test.go.out deleted file mode 100644 index 0a062962d..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/go_test_expect/stmt_test.go.out +++ /dev/null @@ -1,15 +0,0 @@ -********************Stmt Exec******************** -f1:1, f2:abcdefg, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:hello world, f3:641.43, f4:2022-02-08 10:35:43.000623 +0800 CST, f5:false -f1:3, f2:华为, f3:431.54, f4:2022-02-10 19:11:54.000353 +0800 CST, f5:true -f1:4, f2:北京2022冬奥会, f3:5423.52, f4:2022-02-12 06:11:15.000636 +0800 CST, f5:false -f1:5, f2:nanjing, f3:665537.63, f4:2022-02-14 04:51:22.000748 +0800 CST, f5:true -f1:6, f2:研究所, f3:6503.1, f4:2022-02-16 13:45:55.000675 +0800 CST, f5:true -********************Stmt ExecContext******************** -f1:1, f2:abcdefg, f3:123.3, f4:2022-02-08 10:30:43.31 +0800 CST, f5:true -f1:2, f2:hello world, f3:641.43, f4:2022-02-08 10:35:43.000623 +0800 CST, f5:false -f1:3, f2:华为, f3:431.54, f4:2022-02-10 19:11:54.000353 +0800 CST, f5:true -f1:4, f2:北京2022冬奥会, f3:5423.52, f4:2022-02-12 06:11:15.000636 +0800 CST, f5:false -f1:5, f2:nanjing, f3:665537.63, f4:2022-02-14 04:51:22.000748 +0800 CST, f5:true -f1:6, f2:研究所, f3:6503.1, f4:2022-02-16 13:45:55.000675 +0800 CST, f5:true -PASS diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.editorconfig b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.editorconfig deleted file mode 100644 index 433be2a10..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.editorconfig +++ /dev/null @@ -1,9 +0,0 @@ -# http://editorconfig.org - -root = true - -[*] -charset = utf-8 -end_of_line = lf -insert_final_newline = true -trim_trailing_whitespace = true diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/bug_report.yml b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/bug_report.yml deleted file mode 100644 index 9048e7d84..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/bug_report.yml +++ /dev/null @@ -1,51 +0,0 @@ -name: Bug report -description: File a bug report to help us improve -labels: ["bug"] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this bug report! - - - Before you file an issue read the [Contributing guide](https://github.com/go-ini/ini/blob/main/.github/contributing.md). - - Check to make sure someone hasn't already opened a similar [issue](https://github.com/go-ini/ini/issues). - - type: input - attributes: - label: Version - description: Please specify the exact Go module version you're reporting for. - validations: - required: true - - type: textarea - attributes: - label: Describe the bug - description: A clear and concise description of what the bug is. - validations: - required: true - - type: textarea - attributes: - label: To reproduce - description: A code snippet to reproduce the problem described above. - validations: - required: true - - type: textarea - attributes: - label: Expected behavior - description: A clear and concise description of what you expected to happen. - validations: - required: true - - type: textarea - attributes: - label: Additional context - description: | - Links? References? Suggestions? Anything that will give us more context about the issue you are encountering! - - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false - - type: checkboxes - attributes: - label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://go.dev/conduct) - options: - - label: I agree to follow this project's Code of Conduct - required: true diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/config.yml b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/config.yml deleted file mode 100644 index 3ba13e0ce..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/config.yml +++ /dev/null @@ -1 +0,0 @@ -blank_issues_enabled: false diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/documentation.yml b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/documentation.yml deleted file mode 100644 index 1400a6ecc..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/documentation.yml +++ /dev/null @@ -1,30 +0,0 @@ -name: Improve documentation -description: Suggest an idea or a patch for documentation -labels: ["documentation"] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this form! - - - Before you file an issue read the [Contributing guide](https://github.com/go-ini/ini/blob/main/.github/contributing.md). - - Check to make sure someone hasn't already opened a similar [issue](https://github.com/go-ini/ini/issues). - - type: textarea - attributes: - label: What needs to be improved? Please describe - description: A clear and concise description of what is wrong or missing. - validations: - required: true - - type: textarea - attributes: - label: Why do you think it is important? - description: A clear and concise explanation of the rationale. - validations: - required: true - - type: checkboxes - attributes: - label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://go.dev/conduct) - options: - - label: I agree to follow this project's Code of Conduct - required: true diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/feature_request.yml b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/feature_request.yml deleted file mode 100644 index 33896ac38..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/ISSUE_TEMPLATE/feature_request.yml +++ /dev/null @@ -1,45 +0,0 @@ -name: Feature request -description: Suggest an idea for this project -labels: ["feature"] -body: - - type: markdown - attributes: - value: | - Thanks for taking the time to fill out this form! - - - Before you file an issue read the [Contributing guide](https://github.com/go-ini/ini/blob/main/.github/contributing.md). - - Check to make sure someone hasn't already opened a similar [issue](https://github.com/go-ini/ini/issues). - - type: textarea - attributes: - label: Describe the feature - description: A clear and concise description of what the problem is, e.g. I'm always frustrated when [...] - validations: - required: true - - type: textarea - attributes: - label: Describe the solution you'd like - description: A clear and concise description of what you want to happen. - validations: - required: true - - type: textarea - attributes: - label: Describe alternatives you've considered - description: A clear and concise description of any alternative solutions or features you've considered. - validations: - required: true - - type: textarea - attributes: - label: Additional context - description: | - Links? References? Suggestions? Anything that will give us more context about the feature you are requesting! - - Tip: You can attach images or log files by clicking this area to highlight it and then dragging files in. - validations: - required: false - - type: checkboxes - attributes: - label: Code of Conduct - description: By submitting this issue, you agree to follow our [Code of Conduct](https://go.dev/conduct) - options: - - label: I agree to follow this project's Code of Conduct - required: true diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/PULL_REQUEST_TEMPLATE.md b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/PULL_REQUEST_TEMPLATE.md deleted file mode 100644 index 94bb3d374..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/PULL_REQUEST_TEMPLATE.md +++ /dev/null @@ -1,11 +0,0 @@ -### Describe the pull request - -A clear and concise description of what the pull request is about, i.e. what problem should be fixed? - -Link to the issue: - -### Checklist - -- [ ] I agree to follow the [Code of Conduct](https://go.dev/conduct) by submitting this pull request. -- [ ] I have read and acknowledge the [Contributing guide](https://github.com/go-ini/ini/blob/main/.github/contributing.md). -- [ ] I have added test cases to cover the new code. diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/contributing.md b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/contributing.md deleted file mode 100644 index 79a3ee9e8..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/contributing.md +++ /dev/null @@ -1,55 +0,0 @@ -# Welcome to go-ini contributing guide - -Thank you for investing your time in contributing to our projects! - -Read our [Code of Conduct](https://go.dev/conduct) to keep our community approachable and respectable. - -In this guide you will get an overview of the contribution workflow from opening an issue, creating a PR, reviewing, and merging the PR. - -Use the table of contents icon on the top left corner of this document to get to a specific section of this guide quickly. - -## New contributor guide - -To get an overview of the project, read the [README](/README.md). Here are some resources to help you get started with open source contributions: - -- [Finding ways to contribute to open source on GitHub](https://docs.github.com/en/get-started/exploring-projects-on-github/finding-ways-to-contribute-to-open-source-on-github) -- [Set up Git](https://docs.github.com/en/get-started/quickstart/set-up-git) -- [GitHub flow](https://docs.github.com/en/get-started/quickstart/github-flow) -- [Collaborating with pull requests](https://docs.github.com/en/github/collaborating-with-pull-requests) - -In addition to the general guides with open source contributions, you would also need to: - -- Have basic knowledge about INI configuration format and programming in [Go](https://go.dev/). -- Have a working local development setup with a reasonable good IDE or editor like [Visual Studio Code](https://code.visualstudio.com/docs/languages/go), [GoLand](https://www.jetbrains.com/go/) or [Vim](https://github.com/fatih/vim-go). - -## Issues - -### Create a new issue - -- [Check to make sure](https://docs.github.com/en/github/searching-for-information-on-github/searching-on-github/searching-issues-and-pull-requests#search-by-the-title-body-or-comments) someone hasn't already opened a similar [issue](https://github.com/go-ini/ini/issues). -- If a similar issue doesn't exist, open a new issue using a relevant [issue form](https://github.com/go-ini/ini/issues/new/choose). - -### Pick up an issue to solve - -- Scan through our [existing issues](https://github.com/go-ini/ini/issues) to find one that interests you. -- The [good first issue](https://github.com/go-ini/ini/labels/good%20first%20issue) is a good place to start exploring issues that are well-groomed for newcomers. -- Do not hesitate to ask for more details or clarifying questions on the issue! -- Communicate on the issue you are intended to pick up _before_ starting working on it. -- Every issue that gets picked up will have an expected timeline for the implementation, the issue may be reassigned after the expected timeline. Please be responsible and proactive on the communication 🙇‍♂️ - -## Pull requests - -When you're finished with the changes, create a pull request, or a series of pull requests if necessary. - -Contributing to another codebase is not as simple as code changes, it is also about contributing influence to the design. Therefore, we kindly ask you that: - -- Please acknowledge that no pull request is guaranteed to be merged. -- Please always do a self-review before requesting reviews from others. -- Please expect code review to be strict and may have multiple rounds. -- Please make self-contained incremental changes, pull requests with huge diff may be rejected for review. -- Please use English in code comments and docstring. -- Please do not force push unless absolutely necessary. Force pushes make review much harder in multiple rounds, and we use [Squash and merge](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/incorporating-changes-from-a-pull-request/about-pull-request-merges#squash-and-merge-your-pull-request-commits) so you don't need to worry about messy commits and just focus on the changes. - -## Your PR is merged! - -Congratulations 🎉🎉 Thanks again for taking the effort to have this journey with us 🌟 diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/workflows/go.yml b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/workflows/go.yml deleted file mode 100644 index ea1947f4f..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/workflows/go.yml +++ /dev/null @@ -1,60 +0,0 @@ -name: Go -on: - push: - branches: [ main ] - paths: - - '**.go' - - 'go.mod' - - '.golangci.yml' - - '.github/workflows/go.yml' - pull_request: - paths: - - '**.go' - - 'go.mod' - - '.golangci.yml' - - '.github/workflows/go.yml' -env: - GOPROXY: "https://proxy.golang.org" - -jobs: - lint: - name: Lint - runs-on: ubuntu-latest - steps: - - name: Checkout code - uses: actions/checkout@v2 - - name: Init Go Modules - run: | - go mod init github.com/go-ini/ini - go mod tidy - - name: Run golangci-lint - uses: golangci/golangci-lint-action@v2 - with: - version: latest - args: --timeout=30m - skip-pkg-cache: true # Wrokaround of the "tar" problem: https://github.com/golangci/golangci-lint-action/issues/244 - - test: - name: Test - strategy: - matrix: - go-version: [ 1.15.x, 1.16.x, 1.17.x ] - platform: [ ubuntu-latest, macos-latest, windows-latest ] - runs-on: ${{ matrix.platform }} - steps: - - name: Install Go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go-version }} - - name: Checkout code - uses: actions/checkout@v2 - - name: Run tests with coverage - run: | - go mod init github.com/go-ini/ini - go mod tidy - go test -v -race -coverprofile=coverage -covermode=atomic ./... - - name: Upload coverage report to Codecov - uses: codecov/codecov-action@v1.5.0 - with: - file: ./coverage - flags: unittests diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/workflows/lsif.yml b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/workflows/lsif.yml deleted file mode 100644 index 49cefe8b3..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.github/workflows/lsif.yml +++ /dev/null @@ -1,28 +0,0 @@ -name: LSIF -on: - push: - paths: - - '**.go' - - 'go.mod' - - '.github/workflows/lsif.yml' -env: - GOPROXY: "https://proxy.golang.org" - -jobs: - lsif-go: - if: github.repository == 'go-ini/ini' - runs-on: ubuntu-latest - steps: - - uses: actions/checkout@v2 - - name: Generate LSIF data - uses: sourcegraph/lsif-go-action@master - - name: Upload LSIF data to sourcegraph.com - continue-on-error: true - uses: docker://sourcegraph/src-cli:latest - with: - args: lsif upload -github-token=${{ secrets.GITHUB_TOKEN }} - - name: Upload LSIF data to sourcegraph.unknwon.cn - continue-on-error: true - uses: docker://sourcegraph/src-cli:latest - with: - args: -endpoint=https://sourcegraph.unknwon.cn lsif upload -github-token=${{ secrets.GITHUB_TOKEN }} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.gitignore b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.gitignore deleted file mode 100644 index 588388bda..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.gitignore +++ /dev/null @@ -1,7 +0,0 @@ -testdata/conf_out.ini -ini.sublime-project -ini.sublime-workspace -testdata/conf_reflect.ini -.idea -/.vscode -.DS_Store diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.golangci.yml b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.golangci.yml deleted file mode 100644 index b7256bae1..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/.golangci.yml +++ /dev/null @@ -1,21 +0,0 @@ -linters-settings: - nakedret: - max-func-lines: 0 # Disallow any unnamed return statement - -linters: - enable: - - deadcode - - errcheck - - gosimple - - govet - - ineffassign - - staticcheck - - structcheck - - typecheck - - unused - - varcheck - - nakedret - - gofmt - - rowserrcheck - - unconvert - - goimports diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/LICENSE b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/LICENSE deleted file mode 100644 index d361bbcdf..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/LICENSE +++ /dev/null @@ -1,191 +0,0 @@ -Apache License -Version 2.0, January 2004 -http://www.apache.org/licenses/ - -TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION - -1. Definitions. - -"License" shall mean the terms and conditions for use, reproduction, and -distribution as defined by Sections 1 through 9 of this document. - -"Licensor" shall mean the copyright owner or entity authorized by the copyright -owner that is granting the License. - -"Legal Entity" shall mean the union of the acting entity and all other entities -that control, are controlled by, or are under common control with that entity. -For the purposes of this definition, "control" means (i) the power, direct or -indirect, to cause the direction or management of such entity, whether by -contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the -outstanding shares, or (iii) beneficial ownership of such entity. - -"You" (or "Your") shall mean an individual or Legal Entity exercising -permissions granted by this License. - -"Source" form shall mean the preferred form for making modifications, including -but not limited to software source code, documentation source, and configuration -files. - -"Object" form shall mean any form resulting from mechanical transformation or -translation of a Source form, including but not limited to compiled object code, -generated documentation, and conversions to other media types. - -"Work" shall mean the work of authorship, whether in Source or Object form, made -available under the License, as indicated by a copyright notice that is included -in or attached to the work (an example is provided in the Appendix below). - -"Derivative Works" shall mean any work, whether in Source or Object form, that -is based on (or derived from) the Work and for which the editorial revisions, -annotations, elaborations, or other modifications represent, as a whole, an -original work of authorship. For the purposes of this License, Derivative Works -shall not include works that remain separable from, or merely link (or bind by -name) to the interfaces of, the Work and Derivative Works thereof. - -"Contribution" shall mean any work of authorship, including the original version -of the Work and any modifications or additions to that Work or Derivative Works -thereof, that is intentionally submitted to Licensor for inclusion in the Work -by the copyright owner or by an individual or Legal Entity authorized to submit -on behalf of the copyright owner. For the purposes of this definition, -"submitted" means any form of electronic, verbal, or written communication sent -to the Licensor or its representatives, including but not limited to -communication on electronic mailing lists, source code control systems, and -issue tracking systems that are managed by, or on behalf of, the Licensor for -the purpose of discussing and improving the Work, but excluding communication -that is conspicuously marked or otherwise designated in writing by the copyright -owner as "Not a Contribution." - -"Contributor" shall mean Licensor and any individual or Legal Entity on behalf -of whom a Contribution has been received by Licensor and subsequently -incorporated within the Work. - -2. Grant of Copyright License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable copyright license to reproduce, prepare Derivative Works of, -publicly display, publicly perform, sublicense, and distribute the Work and such -Derivative Works in Source or Object form. - -3. Grant of Patent License. - -Subject to the terms and conditions of this License, each Contributor hereby -grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, -irrevocable (except as stated in this section) patent license to make, have -made, use, offer to sell, sell, import, and otherwise transfer the Work, where -such license applies only to those patent claims licensable by such Contributor -that are necessarily infringed by their Contribution(s) alone or by combination -of their Contribution(s) with the Work to which such Contribution(s) was -submitted. If You institute patent litigation against any entity (including a -cross-claim or counterclaim in a lawsuit) alleging that the Work or a -Contribution incorporated within the Work constitutes direct or contributory -patent infringement, then any patent licenses granted to You under this License -for that Work shall terminate as of the date such litigation is filed. - -4. Redistribution. - -You may reproduce and distribute copies of the Work or Derivative Works thereof -in any medium, with or without modifications, and in Source or Object form, -provided that You meet the following conditions: - -You must give any other recipients of the Work or Derivative Works a copy of -this License; and -You must cause any modified files to carry prominent notices stating that You -changed the files; and -You must retain, in the Source form of any Derivative Works that You distribute, -all copyright, patent, trademark, and attribution notices from the Source form -of the Work, excluding those notices that do not pertain to any part of the -Derivative Works; and -If the Work includes a "NOTICE" text file as part of its distribution, then any -Derivative Works that You distribute must include a readable copy of the -attribution notices contained within such NOTICE file, excluding those notices -that do not pertain to any part of the Derivative Works, in at least one of the -following places: within a NOTICE text file distributed as part of the -Derivative Works; within the Source form or documentation, if provided along -with the Derivative Works; or, within a display generated by the Derivative -Works, if and wherever such third-party notices normally appear. The contents of -the NOTICE file are for informational purposes only and do not modify the -License. You may add Your own attribution notices within Derivative Works that -You distribute, alongside or as an addendum to the NOTICE text from the Work, -provided that such additional attribution notices cannot be construed as -modifying the License. -You may add Your own copyright statement to Your modifications and may provide -additional or different license terms and conditions for use, reproduction, or -distribution of Your modifications, or for any such Derivative Works as a whole, -provided Your use, reproduction, and distribution of the Work otherwise complies -with the conditions stated in this License. - -5. Submission of Contributions. - -Unless You explicitly state otherwise, any Contribution intentionally submitted -for inclusion in the Work by You to the Licensor shall be under the terms and -conditions of this License, without any additional terms or conditions. -Notwithstanding the above, nothing herein shall supersede or modify the terms of -any separate license agreement you may have executed with Licensor regarding -such Contributions. - -6. Trademarks. - -This License does not grant permission to use the trade names, trademarks, -service marks, or product names of the Licensor, except as required for -reasonable and customary use in describing the origin of the Work and -reproducing the content of the NOTICE file. - -7. Disclaimer of Warranty. - -Unless required by applicable law or agreed to in writing, Licensor provides the -Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, -WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, -including, without limitation, any warranties or conditions of TITLE, -NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are -solely responsible for determining the appropriateness of using or -redistributing the Work and assume any risks associated with Your exercise of -permissions under this License. - -8. Limitation of Liability. - -In no event and under no legal theory, whether in tort (including negligence), -contract, or otherwise, unless required by applicable law (such as deliberate -and grossly negligent acts) or agreed to in writing, shall any Contributor be -liable to You for damages, including any direct, indirect, special, incidental, -or consequential damages of any character arising as a result of this License or -out of the use or inability to use the Work (including but not limited to -damages for loss of goodwill, work stoppage, computer failure or malfunction, or -any and all other commercial damages or losses), even if such Contributor has -been advised of the possibility of such damages. - -9. Accepting Warranty or Additional Liability. - -While redistributing the Work or Derivative Works thereof, You may choose to -offer, and charge a fee for, acceptance of support, warranty, indemnity, or -other liability obligations and/or rights consistent with this License. However, -in accepting such obligations, You may act only on Your own behalf and on Your -sole responsibility, not on behalf of any other Contributor, and only if You -agree to indemnify, defend, and hold each Contributor harmless for any liability -incurred by, or claims asserted against, such Contributor by reason of your -accepting any such warranty or additional liability. - -END OF TERMS AND CONDITIONS - -APPENDIX: How to apply the Apache License to your work - -To apply the Apache License to your work, attach the following boilerplate -notice, with the fields enclosed by brackets "[]" replaced with your own -identifying information. (Don't include the brackets!) The text should be -enclosed in the appropriate comment syntax for the file format. We also -recommend that a file or class name and description of purpose be included on -the same "printed page" as the copyright notice for easier identification within -third-party archives. - - Copyright 2014 Unknwon - - 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. diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/Makefile b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/Makefile deleted file mode 100644 index f3b0dae2d..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -.PHONY: build test bench vet coverage - -build: vet bench - -test: - go test -v -cover -race - -bench: - go test -v -cover -test.bench=. -test.benchmem - -vet: - go vet - -coverage: - go test -coverprofile=c.out && go tool cover -html=c.out && rm c.out diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/README.md b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/README.md deleted file mode 100644 index 1e4294452..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/README.md +++ /dev/null @@ -1,43 +0,0 @@ -# INI - -[![GitHub Workflow Status](https://img.shields.io/github/workflow/status/go-ini/ini/Go?logo=github&style=for-the-badge)](https://github.com/go-ini/ini/actions?query=workflow%3AGo) -[![codecov](https://img.shields.io/codecov/c/github/go-ini/ini/master?logo=codecov&style=for-the-badge)](https://codecov.io/gh/go-ini/ini) -[![GoDoc](https://img.shields.io/badge/GoDoc-Reference-blue?style=for-the-badge&logo=go)](https://pkg.go.dev/github.com/go-ini/ini?tab=doc) -[![Sourcegraph](https://img.shields.io/badge/view%20on-Sourcegraph-brightgreen.svg?style=for-the-badge&logo=sourcegraph)](https://sourcegraph.com/github.com/go-ini/ini) - -![](https://avatars0.githubusercontent.com/u/10216035?v=3&s=200) - -Package ini provides INI file read and write functionality in Go. - -## Features - -- Load from multiple data sources(file, `[]byte`, `io.Reader` and `io.ReadCloser`) with overwrites. -- Read with recursion values. -- Read with parent-child sections. -- Read with auto-increment key names. -- Read with multiple-line values. -- Read with tons of helper methods. -- Read and convert values to Go types. -- Read and **WRITE** comments of sections and keys. -- Manipulate sections, keys and comments with ease. -- Keep sections and keys in order as you parse and save. - -## Installation - -The minimum requirement of Go is **1.12**. - -```sh -$ go get gopkg.in/ini.v1 -``` - -Please add `-u` flag to update in the future. - -## Getting Help - -- [Getting Started](https://ini.unknwon.io/docs/intro/getting_started) -- [API Documentation](https://gowalker.org/gopkg.in/ini.v1) -- 中国大陆镜像:https://ini.unknwon.cn - -## License - -This project is under Apache v2 License. See the [LICENSE](LICENSE) file for the full license text. diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/codecov.yml b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/codecov.yml deleted file mode 100644 index 31f646ee0..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/codecov.yml +++ /dev/null @@ -1,9 +0,0 @@ -coverage: - range: "60...95" - status: - project: - default: - threshold: 1% - -comment: - layout: 'diff' diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/data_source.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/data_source.go deleted file mode 100644 index 528d0391d..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/data_source.go +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright 2019 Unknwon -// -// 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 ini - -import ( - "bytes" - "fmt" - "io" - "io/ioutil" - "os" -) - -var ( - _ dataSource = (*sourceFile)(nil) - _ dataSource = (*sourceData)(nil) - _ dataSource = (*sourceReadCloser)(nil) -) - -// dataSource is an interface that returns object which can be read and closed. -type dataSource interface { - ReadCloser() (io.ReadCloser, error) -} - -// sourceFile represents an object that contains content on the local file system. -type sourceFile struct { - name string -} - -func (s sourceFile) ReadCloser() (_ io.ReadCloser, err error) { - return os.Open(s.name) -} - -// sourceData represents an object that contains content in memory. -type sourceData struct { - data []byte -} - -func (s *sourceData) ReadCloser() (io.ReadCloser, error) { - return ioutil.NopCloser(bytes.NewReader(s.data)), nil -} - -// sourceReadCloser represents an input stream with Close method. -type sourceReadCloser struct { - reader io.ReadCloser -} - -func (s *sourceReadCloser) ReadCloser() (io.ReadCloser, error) { - return s.reader, nil -} - -func parseDataSource(source interface{}) (dataSource, error) { - switch s := source.(type) { - case string: - return sourceFile{s}, nil - case []byte: - return &sourceData{s}, nil - case io.ReadCloser: - return &sourceReadCloser{s}, nil - case io.Reader: - return &sourceReadCloser{ioutil.NopCloser(s)}, nil - default: - return nil, fmt.Errorf("error parsing data source: unknown type %q", s) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/deprecated.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/deprecated.go deleted file mode 100644 index e8bda06e6..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/deprecated.go +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 Unknwon -// -// 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 ini - -const ( - // Deprecated: Use "DefaultSection" instead. - DEFAULT_SECTION = DefaultSection -) - -var ( - // Deprecated: AllCapsUnderscore converts to format ALL_CAPS_UNDERSCORE. - AllCapsUnderscore = SnackCase -) diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/error.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/error.go deleted file mode 100644 index ff141037f..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/error.go +++ /dev/null @@ -1,34 +0,0 @@ -// Copyright 2016 Unknwon -// -// 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 ini - -import ( - "fmt" -) - -// ErrDelimiterNotFound indicates the error type of no delimiter is found which there should be one. -type ErrDelimiterNotFound struct { - Line string -} - -// IsErrDelimiterNotFound returns true if the given error is an instance of ErrDelimiterNotFound. -func IsErrDelimiterNotFound(err error) bool { - _, ok := err.(ErrDelimiterNotFound) - return ok -} - -func (err ErrDelimiterNotFound) Error() string { - return fmt.Sprintf("key-value delimiter not found: %s", err.Line) -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/file.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/file.go deleted file mode 100644 index 7e5a5bc0b..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/file.go +++ /dev/null @@ -1,524 +0,0 @@ -// Copyright 2017 Unknwon -// -// 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 ini - -import ( - "bytes" - "errors" - "fmt" - "io" - "io/ioutil" - "os" - "strings" - "sync" -) - -// File represents a combination of one or more INI files in memory. -type File struct { - options LoadOptions - dataSources []dataSource - - // Should make things safe, but sometimes doesn't matter. - BlockMode bool - lock sync.RWMutex - - // To keep data in order. - sectionList []string - // To keep track of the index of a section with same name. - // This meta list is only used with non-unique section names are allowed. - sectionIndexes []int - - // Actual data is stored here. - sections map[string][]*Section - - NameMapper - ValueMapper -} - -// newFile initializes File object with given data sources. -func newFile(dataSources []dataSource, opts LoadOptions) *File { - if len(opts.KeyValueDelimiters) == 0 { - opts.KeyValueDelimiters = "=:" - } - if len(opts.KeyValueDelimiterOnWrite) == 0 { - opts.KeyValueDelimiterOnWrite = "=" - } - if len(opts.ChildSectionDelimiter) == 0 { - opts.ChildSectionDelimiter = "." - } - - return &File{ - BlockMode: true, - dataSources: dataSources, - sections: make(map[string][]*Section), - options: opts, - } -} - -// Empty returns an empty file object. -func Empty(opts ...LoadOptions) *File { - var opt LoadOptions - if len(opts) > 0 { - opt = opts[0] - } - - // Ignore error here, we are sure our data is good. - f, _ := LoadSources(opt, []byte("")) - return f -} - -// NewSection creates a new section. -func (f *File) NewSection(name string) (*Section, error) { - if len(name) == 0 { - return nil, errors.New("empty section name") - } - - if (f.options.Insensitive || f.options.InsensitiveSections) && name != DefaultSection { - name = strings.ToLower(name) - } - - if f.BlockMode { - f.lock.Lock() - defer f.lock.Unlock() - } - - if !f.options.AllowNonUniqueSections && inSlice(name, f.sectionList) { - return f.sections[name][0], nil - } - - f.sectionList = append(f.sectionList, name) - - // NOTE: Append to indexes must happen before appending to sections, - // otherwise index will have off-by-one problem. - f.sectionIndexes = append(f.sectionIndexes, len(f.sections[name])) - - sec := newSection(f, name) - f.sections[name] = append(f.sections[name], sec) - - return sec, nil -} - -// NewRawSection creates a new section with an unparseable body. -func (f *File) NewRawSection(name, body string) (*Section, error) { - section, err := f.NewSection(name) - if err != nil { - return nil, err - } - - section.isRawSection = true - section.rawBody = body - return section, nil -} - -// NewSections creates a list of sections. -func (f *File) NewSections(names ...string) (err error) { - for _, name := range names { - if _, err = f.NewSection(name); err != nil { - return err - } - } - return nil -} - -// GetSection returns section by given name. -func (f *File) GetSection(name string) (*Section, error) { - secs, err := f.SectionsByName(name) - if err != nil { - return nil, err - } - - return secs[0], err -} - -// HasSection returns true if the file contains a section with given name. -func (f *File) HasSection(name string) bool { - section, _ := f.GetSection(name) - return section != nil -} - -// SectionsByName returns all sections with given name. -func (f *File) SectionsByName(name string) ([]*Section, error) { - if len(name) == 0 { - name = DefaultSection - } - if f.options.Insensitive || f.options.InsensitiveSections { - name = strings.ToLower(name) - } - - if f.BlockMode { - f.lock.RLock() - defer f.lock.RUnlock() - } - - secs := f.sections[name] - if len(secs) == 0 { - return nil, fmt.Errorf("section %q does not exist", name) - } - - return secs, nil -} - -// Section assumes named section exists and returns a zero-value when not. -func (f *File) Section(name string) *Section { - sec, err := f.GetSection(name) - if err != nil { - if name == "" { - name = DefaultSection - } - sec, _ = f.NewSection(name) - return sec - } - return sec -} - -// SectionWithIndex assumes named section exists and returns a new section when not. -func (f *File) SectionWithIndex(name string, index int) *Section { - secs, err := f.SectionsByName(name) - if err != nil || len(secs) <= index { - // NOTE: It's OK here because the only possible error is empty section name, - // but if it's empty, this piece of code won't be executed. - newSec, _ := f.NewSection(name) - return newSec - } - - return secs[index] -} - -// Sections returns a list of Section stored in the current instance. -func (f *File) Sections() []*Section { - if f.BlockMode { - f.lock.RLock() - defer f.lock.RUnlock() - } - - sections := make([]*Section, len(f.sectionList)) - for i, name := range f.sectionList { - sections[i] = f.sections[name][f.sectionIndexes[i]] - } - return sections -} - -// ChildSections returns a list of child sections of given section name. -func (f *File) ChildSections(name string) []*Section { - return f.Section(name).ChildSections() -} - -// SectionStrings returns list of section names. -func (f *File) SectionStrings() []string { - list := make([]string, len(f.sectionList)) - copy(list, f.sectionList) - return list -} - -// DeleteSection deletes a section or all sections with given name. -func (f *File) DeleteSection(name string) { - secs, err := f.SectionsByName(name) - if err != nil { - return - } - - for i := 0; i < len(secs); i++ { - // For non-unique sections, it is always needed to remove the first one so - // in the next iteration, the subsequent section continue having index 0. - // Ignoring the error as index 0 never returns an error. - _ = f.DeleteSectionWithIndex(name, 0) - } -} - -// DeleteSectionWithIndex deletes a section with given name and index. -func (f *File) DeleteSectionWithIndex(name string, index int) error { - if !f.options.AllowNonUniqueSections && index != 0 { - return fmt.Errorf("delete section with non-zero index is only allowed when non-unique sections is enabled") - } - - if len(name) == 0 { - name = DefaultSection - } - if f.options.Insensitive || f.options.InsensitiveSections { - name = strings.ToLower(name) - } - - if f.BlockMode { - f.lock.Lock() - defer f.lock.Unlock() - } - - // Count occurrences of the sections - occurrences := 0 - - sectionListCopy := make([]string, len(f.sectionList)) - copy(sectionListCopy, f.sectionList) - - for i, s := range sectionListCopy { - if s != name { - continue - } - - if occurrences == index { - if len(f.sections[name]) <= 1 { - delete(f.sections, name) // The last one in the map - } else { - f.sections[name] = append(f.sections[name][:index], f.sections[name][index+1:]...) - } - - // Fix section lists - f.sectionList = append(f.sectionList[:i], f.sectionList[i+1:]...) - f.sectionIndexes = append(f.sectionIndexes[:i], f.sectionIndexes[i+1:]...) - - } else if occurrences > index { - // Fix the indices of all following sections with this name. - f.sectionIndexes[i-1]-- - } - - occurrences++ - } - - return nil -} - -func (f *File) reload(s dataSource) error { - r, err := s.ReadCloser() - if err != nil { - return err - } - defer r.Close() - - return f.parse(r) -} - -// Reload reloads and parses all data sources. -func (f *File) Reload() (err error) { - for _, s := range f.dataSources { - if err = f.reload(s); err != nil { - // In loose mode, we create an empty default section for nonexistent files. - if os.IsNotExist(err) && f.options.Loose { - _ = f.parse(bytes.NewBuffer(nil)) - continue - } - return err - } - if f.options.ShortCircuit { - return nil - } - } - return nil -} - -// Append appends one or more data sources and reloads automatically. -func (f *File) Append(source interface{}, others ...interface{}) error { - ds, err := parseDataSource(source) - if err != nil { - return err - } - f.dataSources = append(f.dataSources, ds) - for _, s := range others { - ds, err = parseDataSource(s) - if err != nil { - return err - } - f.dataSources = append(f.dataSources, ds) - } - return f.Reload() -} - -func (f *File) writeToBuffer(indent string) (*bytes.Buffer, error) { - equalSign := DefaultFormatLeft + f.options.KeyValueDelimiterOnWrite + DefaultFormatRight - - if PrettyFormat || PrettyEqual { - equalSign = fmt.Sprintf(" %s ", f.options.KeyValueDelimiterOnWrite) - } - - // Use buffer to make sure target is safe until finish encoding. - buf := bytes.NewBuffer(nil) - for i, sname := range f.sectionList { - sec := f.SectionWithIndex(sname, f.sectionIndexes[i]) - if len(sec.Comment) > 0 { - // Support multiline comments - lines := strings.Split(sec.Comment, LineBreak) - for i := range lines { - if lines[i][0] != '#' && lines[i][0] != ';' { - lines[i] = "; " + lines[i] - } else { - lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) - } - - if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { - return nil, err - } - } - } - - if i > 0 || DefaultHeader || (i == 0 && strings.ToUpper(sec.name) != DefaultSection) { - if _, err := buf.WriteString("[" + sname + "]" + LineBreak); err != nil { - return nil, err - } - } else { - // Write nothing if default section is empty - if len(sec.keyList) == 0 { - continue - } - } - - if sec.isRawSection { - if _, err := buf.WriteString(sec.rawBody); err != nil { - return nil, err - } - - if PrettySection { - // Put a line between sections - if _, err := buf.WriteString(LineBreak); err != nil { - return nil, err - } - } - continue - } - - // Count and generate alignment length and buffer spaces using the - // longest key. Keys may be modified if they contain certain characters so - // we need to take that into account in our calculation. - alignLength := 0 - if PrettyFormat { - for _, kname := range sec.keyList { - keyLength := len(kname) - // First case will surround key by ` and second by """ - if strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters) { - keyLength += 2 - } else if strings.Contains(kname, "`") { - keyLength += 6 - } - - if keyLength > alignLength { - alignLength = keyLength - } - } - } - alignSpaces := bytes.Repeat([]byte(" "), alignLength) - - KeyList: - for _, kname := range sec.keyList { - key := sec.Key(kname) - if len(key.Comment) > 0 { - if len(indent) > 0 && sname != DefaultSection { - buf.WriteString(indent) - } - - // Support multiline comments - lines := strings.Split(key.Comment, LineBreak) - for i := range lines { - if lines[i][0] != '#' && lines[i][0] != ';' { - lines[i] = "; " + strings.TrimSpace(lines[i]) - } else { - lines[i] = lines[i][:1] + " " + strings.TrimSpace(lines[i][1:]) - } - - if _, err := buf.WriteString(lines[i] + LineBreak); err != nil { - return nil, err - } - } - } - - if len(indent) > 0 && sname != DefaultSection { - buf.WriteString(indent) - } - - switch { - case key.isAutoIncrement: - kname = "-" - case strings.Contains(kname, "\"") || strings.ContainsAny(kname, f.options.KeyValueDelimiters): - kname = "`" + kname + "`" - case strings.Contains(kname, "`"): - kname = `"""` + kname + `"""` - } - - for _, val := range key.ValueWithShadows() { - if _, err := buf.WriteString(kname); err != nil { - return nil, err - } - - if key.isBooleanType { - if kname != sec.keyList[len(sec.keyList)-1] { - buf.WriteString(LineBreak) - } - continue KeyList - } - - // Write out alignment spaces before "=" sign - if PrettyFormat { - buf.Write(alignSpaces[:alignLength-len(kname)]) - } - - // In case key value contains "\n", "`", "\"", "#" or ";" - if strings.ContainsAny(val, "\n`") { - val = `"""` + val + `"""` - } else if !f.options.IgnoreInlineComment && strings.ContainsAny(val, "#;") { - val = "`" + val + "`" - } else if len(strings.TrimSpace(val)) != len(val) { - val = `"` + val + `"` - } - if _, err := buf.WriteString(equalSign + val + LineBreak); err != nil { - return nil, err - } - } - - for _, val := range key.nestedValues { - if _, err := buf.WriteString(indent + " " + val + LineBreak); err != nil { - return nil, err - } - } - } - - if PrettySection { - // Put a line between sections - if _, err := buf.WriteString(LineBreak); err != nil { - return nil, err - } - } - } - - return buf, nil -} - -// WriteToIndent writes content into io.Writer with given indention. -// If PrettyFormat has been set to be true, -// it will align "=" sign with spaces under each section. -func (f *File) WriteToIndent(w io.Writer, indent string) (int64, error) { - buf, err := f.writeToBuffer(indent) - if err != nil { - return 0, err - } - return buf.WriteTo(w) -} - -// WriteTo writes file content into io.Writer. -func (f *File) WriteTo(w io.Writer) (int64, error) { - return f.WriteToIndent(w, "") -} - -// SaveToIndent writes content to file system with given value indention. -func (f *File) SaveToIndent(filename, indent string) error { - // Note: Because we are truncating with os.Create, - // so it's safer to save to a temporary file location and rename after done. - buf, err := f.writeToBuffer(indent) - if err != nil { - return err - } - - return ioutil.WriteFile(filename, buf.Bytes(), 0666) -} - -// SaveTo writes content to file system. -func (f *File) SaveTo(filename string) error { - return f.SaveToIndent(filename, "") -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/helper.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/helper.go deleted file mode 100644 index f9d80a682..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/helper.go +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019 Unknwon -// -// 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 ini - -func inSlice(str string, s []string) bool { - for _, v := range s { - if str == v { - return true - } - } - return false -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/ini.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/ini.go deleted file mode 100644 index c32047ce4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/ini.go +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright 2014 Unknwon -// -// 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 ini provides INI file read and write functionality in Go. -package ini - -import ( - "os" - "regexp" - "runtime" - "strings" -) - -const ( - // DefaultSection is the name of default section. You can use this constant or the string literal. - // In most of cases, an empty string is all you need to access the section. - DefaultSection = "DEFAULT" - - // Maximum allowed depth when recursively substituing variable names. - depthValues = 99 -) - -var ( - // LineBreak is the delimiter to determine or compose a new line. - // This variable will be changed to "\r\n" automatically on Windows at package init time. - LineBreak = "\n" - - // Variable regexp pattern: %(variable)s - varPattern = regexp.MustCompile(`%\(([^)]+)\)s`) - - // DefaultHeader explicitly writes default section header. - DefaultHeader = false - - // PrettySection indicates whether to put a line between sections. - PrettySection = true - // PrettyFormat indicates whether to align "=" sign with spaces to produce pretty output - // or reduce all possible spaces for compact format. - PrettyFormat = true - // PrettyEqual places spaces around "=" sign even when PrettyFormat is false. - PrettyEqual = false - // DefaultFormatLeft places custom spaces on the left when PrettyFormat and PrettyEqual are both disabled. - DefaultFormatLeft = "" - // DefaultFormatRight places custom spaces on the right when PrettyFormat and PrettyEqual are both disabled. - DefaultFormatRight = "" -) - -var inTest = len(os.Args) > 0 && strings.HasSuffix(strings.TrimSuffix(os.Args[0], ".exe"), ".test") - -func init() { - if runtime.GOOS == "windows" && !inTest { - LineBreak = "\r\n" - } -} - -// LoadOptions contains all customized options used for load data source(s). -type LoadOptions struct { - // Loose indicates whether the parser should ignore nonexistent files or return error. - Loose bool - // Insensitive indicates whether the parser forces all section and key names to lowercase. - Insensitive bool - // InsensitiveSections indicates whether the parser forces all section to lowercase. - InsensitiveSections bool - // InsensitiveKeys indicates whether the parser forces all key names to lowercase. - InsensitiveKeys bool - // IgnoreContinuation indicates whether to ignore continuation lines while parsing. - IgnoreContinuation bool - // IgnoreInlineComment indicates whether to ignore comments at the end of value and treat it as part of value. - IgnoreInlineComment bool - // SkipUnrecognizableLines indicates whether to skip unrecognizable lines that do not conform to key/value pairs. - SkipUnrecognizableLines bool - // ShortCircuit indicates whether to ignore other configuration sources after loaded the first available configuration source. - ShortCircuit bool - // AllowBooleanKeys indicates whether to allow boolean type keys or treat as value is missing. - // This type of keys are mostly used in my.cnf. - AllowBooleanKeys bool - // AllowShadows indicates whether to keep track of keys with same name under same section. - AllowShadows bool - // AllowNestedValues indicates whether to allow AWS-like nested values. - // Docs: http://docs.aws.amazon.com/cli/latest/topic/config-vars.html#nested-values - AllowNestedValues bool - // AllowPythonMultilineValues indicates whether to allow Python-like multi-line values. - // Docs: https://docs.python.org/3/library/configparser.html#supported-ini-file-structure - // Relevant quote: Values can also span multiple lines, as long as they are indented deeper - // than the first line of the value. - AllowPythonMultilineValues bool - // SpaceBeforeInlineComment indicates whether to allow comment symbols (\# and \;) inside value. - // Docs: https://docs.python.org/2/library/configparser.html - // Quote: Comments may appear on their own in an otherwise empty line, or may be entered in lines holding values or section names. - // In the latter case, they need to be preceded by a whitespace character to be recognized as a comment. - SpaceBeforeInlineComment bool - // UnescapeValueDoubleQuotes indicates whether to unescape double quotes inside value to regular format - // when value is surrounded by double quotes, e.g. key="a \"value\"" => key=a "value" - UnescapeValueDoubleQuotes bool - // UnescapeValueCommentSymbols indicates to unescape comment symbols (\# and \;) inside value to regular format - // when value is NOT surrounded by any quotes. - // Note: UNSTABLE, behavior might change to only unescape inside double quotes but may noy necessary at all. - UnescapeValueCommentSymbols bool - // UnparseableSections stores a list of blocks that are allowed with raw content which do not otherwise - // conform to key/value pairs. Specify the names of those blocks here. - UnparseableSections []string - // KeyValueDelimiters is the sequence of delimiters that are used to separate key and value. By default, it is "=:". - KeyValueDelimiters string - // KeyValueDelimiterOnWrite is the delimiter that are used to separate key and value output. By default, it is "=". - KeyValueDelimiterOnWrite string - // ChildSectionDelimiter is the delimiter that is used to separate child sections. By default, it is ".". - ChildSectionDelimiter string - // PreserveSurroundedQuote indicates whether to preserve surrounded quote (single and double quotes). - PreserveSurroundedQuote bool - // DebugFunc is called to collect debug information (currently only useful to debug parsing Python-style multiline values). - DebugFunc DebugFunc - // ReaderBufferSize is the buffer size of the reader in bytes. - ReaderBufferSize int - // AllowNonUniqueSections indicates whether to allow sections with the same name multiple times. - AllowNonUniqueSections bool - // AllowDuplicateShadowValues indicates whether values for shadowed keys should be deduplicated. - AllowDuplicateShadowValues bool -} - -// DebugFunc is the type of function called to log parse events. -type DebugFunc func(message string) - -// LoadSources allows caller to apply customized options for loading from data source(s). -func LoadSources(opts LoadOptions, source interface{}, others ...interface{}) (_ *File, err error) { - sources := make([]dataSource, len(others)+1) - sources[0], err = parseDataSource(source) - if err != nil { - return nil, err - } - for i := range others { - sources[i+1], err = parseDataSource(others[i]) - if err != nil { - return nil, err - } - } - f := newFile(sources, opts) - if err = f.Reload(); err != nil { - return nil, err - } - return f, nil -} - -// Load loads and parses from INI data sources. -// Arguments can be mixed of file name with string type, or raw data in []byte. -// It will return error if list contains nonexistent files. -func Load(source interface{}, others ...interface{}) (*File, error) { - return LoadSources(LoadOptions{}, source, others...) -} - -// LooseLoad has exactly same functionality as Load function -// except it ignores nonexistent files instead of returning error. -func LooseLoad(source interface{}, others ...interface{}) (*File, error) { - return LoadSources(LoadOptions{Loose: true}, source, others...) -} - -// InsensitiveLoad has exactly same functionality as Load function -// except it forces all section and key names to be lowercased. -func InsensitiveLoad(source interface{}, others ...interface{}) (*File, error) { - return LoadSources(LoadOptions{Insensitive: true}, source, others...) -} - -// ShadowLoad has exactly same functionality as Load function -// except it allows have shadow keys. -func ShadowLoad(source interface{}, others ...interface{}) (*File, error) { - return LoadSources(LoadOptions{AllowShadows: true}, source, others...) -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/key.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/key.go deleted file mode 100644 index 19ceb5ed6..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/key.go +++ /dev/null @@ -1,828 +0,0 @@ -// Copyright 2014 Unknwon -// -// 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 ini - -import ( - "bytes" - "errors" - "fmt" - "strconv" - "strings" - "time" -) - -// Key represents a key under a section. -type Key struct { - s *Section - Comment string - name string - value string - isAutoIncrement bool - isBooleanType bool - - isShadow bool - shadows []*Key - - nestedValues []string -} - -// newKey simply return a key object with given values. -func newKey(s *Section, name, val string) *Key { - return &Key{ - s: s, - name: name, - value: val, - } -} - -func (k *Key) addShadow(val string) error { - if k.isShadow { - return errors.New("cannot add shadow to another shadow key") - } else if k.isAutoIncrement || k.isBooleanType { - return errors.New("cannot add shadow to auto-increment or boolean key") - } - - if !k.s.f.options.AllowDuplicateShadowValues { - // Deduplicate shadows based on their values. - if k.value == val { - return nil - } - for i := range k.shadows { - if k.shadows[i].value == val { - return nil - } - } - } - - shadow := newKey(k.s, k.name, val) - shadow.isShadow = true - k.shadows = append(k.shadows, shadow) - return nil -} - -// AddShadow adds a new shadow key to itself. -func (k *Key) AddShadow(val string) error { - if !k.s.f.options.AllowShadows { - return errors.New("shadow key is not allowed") - } - return k.addShadow(val) -} - -func (k *Key) addNestedValue(val string) error { - if k.isAutoIncrement || k.isBooleanType { - return errors.New("cannot add nested value to auto-increment or boolean key") - } - - k.nestedValues = append(k.nestedValues, val) - return nil -} - -// AddNestedValue adds a nested value to the key. -func (k *Key) AddNestedValue(val string) error { - if !k.s.f.options.AllowNestedValues { - return errors.New("nested value is not allowed") - } - return k.addNestedValue(val) -} - -// ValueMapper represents a mapping function for values, e.g. os.ExpandEnv -type ValueMapper func(string) string - -// Name returns name of key. -func (k *Key) Name() string { - return k.name -} - -// Value returns raw value of key for performance purpose. -func (k *Key) Value() string { - return k.value -} - -// ValueWithShadows returns raw values of key and its shadows if any. -func (k *Key) ValueWithShadows() []string { - if len(k.shadows) == 0 { - return []string{k.value} - } - vals := make([]string, len(k.shadows)+1) - vals[0] = k.value - for i := range k.shadows { - vals[i+1] = k.shadows[i].value - } - return vals -} - -// NestedValues returns nested values stored in the key. -// It is possible returned value is nil if no nested values stored in the key. -func (k *Key) NestedValues() []string { - return k.nestedValues -} - -// transformValue takes a raw value and transforms to its final string. -func (k *Key) transformValue(val string) string { - if k.s.f.ValueMapper != nil { - val = k.s.f.ValueMapper(val) - } - - // Fail-fast if no indicate char found for recursive value - if !strings.Contains(val, "%") { - return val - } - for i := 0; i < depthValues; i++ { - vr := varPattern.FindString(val) - if len(vr) == 0 { - break - } - - // Take off leading '%(' and trailing ')s'. - noption := vr[2 : len(vr)-2] - - // Search in the same section. - // If not found or found the key itself, then search again in default section. - nk, err := k.s.GetKey(noption) - if err != nil || k == nk { - nk, _ = k.s.f.Section("").GetKey(noption) - if nk == nil { - // Stop when no results found in the default section, - // and returns the value as-is. - break - } - } - - // Substitute by new value and take off leading '%(' and trailing ')s'. - val = strings.Replace(val, vr, nk.value, -1) - } - return val -} - -// String returns string representation of value. -func (k *Key) String() string { - return k.transformValue(k.value) -} - -// Validate accepts a validate function which can -// return modifed result as key value. -func (k *Key) Validate(fn func(string) string) string { - return fn(k.String()) -} - -// parseBool returns the boolean value represented by the string. -// -// It accepts 1, t, T, TRUE, true, True, YES, yes, Yes, y, ON, on, On, -// 0, f, F, FALSE, false, False, NO, no, No, n, OFF, off, Off. -// Any other value returns an error. -func parseBool(str string) (value bool, err error) { - switch str { - case "1", "t", "T", "true", "TRUE", "True", "YES", "yes", "Yes", "y", "ON", "on", "On": - return true, nil - case "0", "f", "F", "false", "FALSE", "False", "NO", "no", "No", "n", "OFF", "off", "Off": - return false, nil - } - return false, fmt.Errorf("parsing \"%s\": invalid syntax", str) -} - -// Bool returns bool type value. -func (k *Key) Bool() (bool, error) { - return parseBool(k.String()) -} - -// Float64 returns float64 type value. -func (k *Key) Float64() (float64, error) { - return strconv.ParseFloat(k.String(), 64) -} - -// Int returns int type value. -func (k *Key) Int() (int, error) { - v, err := strconv.ParseInt(k.String(), 0, 64) - return int(v), err -} - -// Int64 returns int64 type value. -func (k *Key) Int64() (int64, error) { - return strconv.ParseInt(k.String(), 0, 64) -} - -// Uint returns uint type valued. -func (k *Key) Uint() (uint, error) { - u, e := strconv.ParseUint(k.String(), 0, 64) - return uint(u), e -} - -// Uint64 returns uint64 type value. -func (k *Key) Uint64() (uint64, error) { - return strconv.ParseUint(k.String(), 0, 64) -} - -// Duration returns time.Duration type value. -func (k *Key) Duration() (time.Duration, error) { - return time.ParseDuration(k.String()) -} - -// TimeFormat parses with given format and returns time.Time type value. -func (k *Key) TimeFormat(format string) (time.Time, error) { - return time.Parse(format, k.String()) -} - -// Time parses with RFC3339 format and returns time.Time type value. -func (k *Key) Time() (time.Time, error) { - return k.TimeFormat(time.RFC3339) -} - -// MustString returns default value if key value is empty. -func (k *Key) MustString(defaultVal string) string { - val := k.String() - if len(val) == 0 { - k.value = defaultVal - return defaultVal - } - return val -} - -// MustBool always returns value without error, -// it returns false if error occurs. -func (k *Key) MustBool(defaultVal ...bool) bool { - val, err := k.Bool() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatBool(defaultVal[0]) - return defaultVal[0] - } - return val -} - -// MustFloat64 always returns value without error, -// it returns 0.0 if error occurs. -func (k *Key) MustFloat64(defaultVal ...float64) float64 { - val, err := k.Float64() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatFloat(defaultVal[0], 'f', -1, 64) - return defaultVal[0] - } - return val -} - -// MustInt always returns value without error, -// it returns 0 if error occurs. -func (k *Key) MustInt(defaultVal ...int) int { - val, err := k.Int() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatInt(int64(defaultVal[0]), 10) - return defaultVal[0] - } - return val -} - -// MustInt64 always returns value without error, -// it returns 0 if error occurs. -func (k *Key) MustInt64(defaultVal ...int64) int64 { - val, err := k.Int64() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatInt(defaultVal[0], 10) - return defaultVal[0] - } - return val -} - -// MustUint always returns value without error, -// it returns 0 if error occurs. -func (k *Key) MustUint(defaultVal ...uint) uint { - val, err := k.Uint() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatUint(uint64(defaultVal[0]), 10) - return defaultVal[0] - } - return val -} - -// MustUint64 always returns value without error, -// it returns 0 if error occurs. -func (k *Key) MustUint64(defaultVal ...uint64) uint64 { - val, err := k.Uint64() - if len(defaultVal) > 0 && err != nil { - k.value = strconv.FormatUint(defaultVal[0], 10) - return defaultVal[0] - } - return val -} - -// MustDuration always returns value without error, -// it returns zero value if error occurs. -func (k *Key) MustDuration(defaultVal ...time.Duration) time.Duration { - val, err := k.Duration() - if len(defaultVal) > 0 && err != nil { - k.value = defaultVal[0].String() - return defaultVal[0] - } - return val -} - -// MustTimeFormat always parses with given format and returns value without error, -// it returns zero value if error occurs. -func (k *Key) MustTimeFormat(format string, defaultVal ...time.Time) time.Time { - val, err := k.TimeFormat(format) - if len(defaultVal) > 0 && err != nil { - k.value = defaultVal[0].Format(format) - return defaultVal[0] - } - return val -} - -// MustTime always parses with RFC3339 format and returns value without error, -// it returns zero value if error occurs. -func (k *Key) MustTime(defaultVal ...time.Time) time.Time { - return k.MustTimeFormat(time.RFC3339, defaultVal...) -} - -// In always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) In(defaultVal string, candidates []string) string { - val := k.String() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InFloat64 always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InFloat64(defaultVal float64, candidates []float64) float64 { - val := k.MustFloat64() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InInt always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InInt(defaultVal int, candidates []int) int { - val := k.MustInt() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InInt64 always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InInt64(defaultVal int64, candidates []int64) int64 { - val := k.MustInt64() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InUint always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InUint(defaultVal uint, candidates []uint) uint { - val := k.MustUint() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InUint64 always returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InUint64(defaultVal uint64, candidates []uint64) uint64 { - val := k.MustUint64() - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InTimeFormat always parses with given format and returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InTimeFormat(format string, defaultVal time.Time, candidates []time.Time) time.Time { - val := k.MustTimeFormat(format) - for _, cand := range candidates { - if val == cand { - return val - } - } - return defaultVal -} - -// InTime always parses with RFC3339 format and returns value without error, -// it returns default value if error occurs or doesn't fit into candidates. -func (k *Key) InTime(defaultVal time.Time, candidates []time.Time) time.Time { - return k.InTimeFormat(time.RFC3339, defaultVal, candidates) -} - -// RangeFloat64 checks if value is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeFloat64(defaultVal, min, max float64) float64 { - val := k.MustFloat64() - if val < min || val > max { - return defaultVal - } - return val -} - -// RangeInt checks if value is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeInt(defaultVal, min, max int) int { - val := k.MustInt() - if val < min || val > max { - return defaultVal - } - return val -} - -// RangeInt64 checks if value is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeInt64(defaultVal, min, max int64) int64 { - val := k.MustInt64() - if val < min || val > max { - return defaultVal - } - return val -} - -// RangeTimeFormat checks if value with given format is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeTimeFormat(format string, defaultVal, min, max time.Time) time.Time { - val := k.MustTimeFormat(format) - if val.Unix() < min.Unix() || val.Unix() > max.Unix() { - return defaultVal - } - return val -} - -// RangeTime checks if value with RFC3339 format is in given range inclusively, -// and returns default value if it's not. -func (k *Key) RangeTime(defaultVal, min, max time.Time) time.Time { - return k.RangeTimeFormat(time.RFC3339, defaultVal, min, max) -} - -// Strings returns list of string divided by given delimiter. -func (k *Key) Strings(delim string) []string { - str := k.String() - if len(str) == 0 { - return []string{} - } - - runes := []rune(str) - vals := make([]string, 0, 2) - var buf bytes.Buffer - escape := false - idx := 0 - for { - if escape { - escape = false - if runes[idx] != '\\' && !strings.HasPrefix(string(runes[idx:]), delim) { - buf.WriteRune('\\') - } - buf.WriteRune(runes[idx]) - } else { - if runes[idx] == '\\' { - escape = true - } else if strings.HasPrefix(string(runes[idx:]), delim) { - idx += len(delim) - 1 - vals = append(vals, strings.TrimSpace(buf.String())) - buf.Reset() - } else { - buf.WriteRune(runes[idx]) - } - } - idx++ - if idx == len(runes) { - break - } - } - - if buf.Len() > 0 { - vals = append(vals, strings.TrimSpace(buf.String())) - } - - return vals -} - -// StringsWithShadows returns list of string divided by given delimiter. -// Shadows will also be appended if any. -func (k *Key) StringsWithShadows(delim string) []string { - vals := k.ValueWithShadows() - results := make([]string, 0, len(vals)*2) - for i := range vals { - if len(vals) == 0 { - continue - } - - results = append(results, strings.Split(vals[i], delim)...) - } - - for i := range results { - results[i] = k.transformValue(strings.TrimSpace(results[i])) - } - return results -} - -// Float64s returns list of float64 divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Float64s(delim string) []float64 { - vals, _ := k.parseFloat64s(k.Strings(delim), true, false) - return vals -} - -// Ints returns list of int divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Ints(delim string) []int { - vals, _ := k.parseInts(k.Strings(delim), true, false) - return vals -} - -// Int64s returns list of int64 divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Int64s(delim string) []int64 { - vals, _ := k.parseInt64s(k.Strings(delim), true, false) - return vals -} - -// Uints returns list of uint divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Uints(delim string) []uint { - vals, _ := k.parseUints(k.Strings(delim), true, false) - return vals -} - -// Uint64s returns list of uint64 divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Uint64s(delim string) []uint64 { - vals, _ := k.parseUint64s(k.Strings(delim), true, false) - return vals -} - -// Bools returns list of bool divided by given delimiter. Any invalid input will be treated as zero value. -func (k *Key) Bools(delim string) []bool { - vals, _ := k.parseBools(k.Strings(delim), true, false) - return vals -} - -// TimesFormat parses with given format and returns list of time.Time divided by given delimiter. -// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). -func (k *Key) TimesFormat(format, delim string) []time.Time { - vals, _ := k.parseTimesFormat(format, k.Strings(delim), true, false) - return vals -} - -// Times parses with RFC3339 format and returns list of time.Time divided by given delimiter. -// Any invalid input will be treated as zero value (0001-01-01 00:00:00 +0000 UTC). -func (k *Key) Times(delim string) []time.Time { - return k.TimesFormat(time.RFC3339, delim) -} - -// ValidFloat64s returns list of float64 divided by given delimiter. If some value is not float, then -// it will not be included to result list. -func (k *Key) ValidFloat64s(delim string) []float64 { - vals, _ := k.parseFloat64s(k.Strings(delim), false, false) - return vals -} - -// ValidInts returns list of int divided by given delimiter. If some value is not integer, then it will -// not be included to result list. -func (k *Key) ValidInts(delim string) []int { - vals, _ := k.parseInts(k.Strings(delim), false, false) - return vals -} - -// ValidInt64s returns list of int64 divided by given delimiter. If some value is not 64-bit integer, -// then it will not be included to result list. -func (k *Key) ValidInt64s(delim string) []int64 { - vals, _ := k.parseInt64s(k.Strings(delim), false, false) - return vals -} - -// ValidUints returns list of uint divided by given delimiter. If some value is not unsigned integer, -// then it will not be included to result list. -func (k *Key) ValidUints(delim string) []uint { - vals, _ := k.parseUints(k.Strings(delim), false, false) - return vals -} - -// ValidUint64s returns list of uint64 divided by given delimiter. If some value is not 64-bit unsigned -// integer, then it will not be included to result list. -func (k *Key) ValidUint64s(delim string) []uint64 { - vals, _ := k.parseUint64s(k.Strings(delim), false, false) - return vals -} - -// ValidBools returns list of bool divided by given delimiter. If some value is not 64-bit unsigned -// integer, then it will not be included to result list. -func (k *Key) ValidBools(delim string) []bool { - vals, _ := k.parseBools(k.Strings(delim), false, false) - return vals -} - -// ValidTimesFormat parses with given format and returns list of time.Time divided by given delimiter. -func (k *Key) ValidTimesFormat(format, delim string) []time.Time { - vals, _ := k.parseTimesFormat(format, k.Strings(delim), false, false) - return vals -} - -// ValidTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter. -func (k *Key) ValidTimes(delim string) []time.Time { - return k.ValidTimesFormat(time.RFC3339, delim) -} - -// StrictFloat64s returns list of float64 divided by given delimiter or error on first invalid input. -func (k *Key) StrictFloat64s(delim string) ([]float64, error) { - return k.parseFloat64s(k.Strings(delim), false, true) -} - -// StrictInts returns list of int divided by given delimiter or error on first invalid input. -func (k *Key) StrictInts(delim string) ([]int, error) { - return k.parseInts(k.Strings(delim), false, true) -} - -// StrictInt64s returns list of int64 divided by given delimiter or error on first invalid input. -func (k *Key) StrictInt64s(delim string) ([]int64, error) { - return k.parseInt64s(k.Strings(delim), false, true) -} - -// StrictUints returns list of uint divided by given delimiter or error on first invalid input. -func (k *Key) StrictUints(delim string) ([]uint, error) { - return k.parseUints(k.Strings(delim), false, true) -} - -// StrictUint64s returns list of uint64 divided by given delimiter or error on first invalid input. -func (k *Key) StrictUint64s(delim string) ([]uint64, error) { - return k.parseUint64s(k.Strings(delim), false, true) -} - -// StrictBools returns list of bool divided by given delimiter or error on first invalid input. -func (k *Key) StrictBools(delim string) ([]bool, error) { - return k.parseBools(k.Strings(delim), false, true) -} - -// StrictTimesFormat parses with given format and returns list of time.Time divided by given delimiter -// or error on first invalid input. -func (k *Key) StrictTimesFormat(format, delim string) ([]time.Time, error) { - return k.parseTimesFormat(format, k.Strings(delim), false, true) -} - -// StrictTimes parses with RFC3339 format and returns list of time.Time divided by given delimiter -// or error on first invalid input. -func (k *Key) StrictTimes(delim string) ([]time.Time, error) { - return k.StrictTimesFormat(time.RFC3339, delim) -} - -// parseBools transforms strings to bools. -func (k *Key) parseBools(strs []string, addInvalid, returnOnInvalid bool) ([]bool, error) { - vals := make([]bool, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := parseBool(str) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(bool)) - } - } - return vals, err -} - -// parseFloat64s transforms strings to float64s. -func (k *Key) parseFloat64s(strs []string, addInvalid, returnOnInvalid bool) ([]float64, error) { - vals := make([]float64, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseFloat(str, 64) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(float64)) - } - } - return vals, err -} - -// parseInts transforms strings to ints. -func (k *Key) parseInts(strs []string, addInvalid, returnOnInvalid bool) ([]int, error) { - vals := make([]int, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseInt(str, 0, 64) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, int(val.(int64))) - } - } - return vals, err -} - -// parseInt64s transforms strings to int64s. -func (k *Key) parseInt64s(strs []string, addInvalid, returnOnInvalid bool) ([]int64, error) { - vals := make([]int64, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseInt(str, 0, 64) - return val, err - } - - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(int64)) - } - } - return vals, err -} - -// parseUints transforms strings to uints. -func (k *Key) parseUints(strs []string, addInvalid, returnOnInvalid bool) ([]uint, error) { - vals := make([]uint, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseUint(str, 0, 64) - return val, err - } - - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, uint(val.(uint64))) - } - } - return vals, err -} - -// parseUint64s transforms strings to uint64s. -func (k *Key) parseUint64s(strs []string, addInvalid, returnOnInvalid bool) ([]uint64, error) { - vals := make([]uint64, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := strconv.ParseUint(str, 0, 64) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(uint64)) - } - } - return vals, err -} - -type Parser func(str string) (interface{}, error) - -// parseTimesFormat transforms strings to times in given format. -func (k *Key) parseTimesFormat(format string, strs []string, addInvalid, returnOnInvalid bool) ([]time.Time, error) { - vals := make([]time.Time, 0, len(strs)) - parser := func(str string) (interface{}, error) { - val, err := time.Parse(format, str) - return val, err - } - rawVals, err := k.doParse(strs, addInvalid, returnOnInvalid, parser) - if err == nil { - for _, val := range rawVals { - vals = append(vals, val.(time.Time)) - } - } - return vals, err -} - -// doParse transforms strings to different types -func (k *Key) doParse(strs []string, addInvalid, returnOnInvalid bool, parser Parser) ([]interface{}, error) { - vals := make([]interface{}, 0, len(strs)) - for _, str := range strs { - val, err := parser(str) - if err != nil && returnOnInvalid { - return nil, err - } - if err == nil || addInvalid { - vals = append(vals, val) - } - } - return vals, nil -} - -// SetValue changes key value. -func (k *Key) SetValue(v string) { - if k.s.f.BlockMode { - k.s.f.lock.Lock() - defer k.s.f.lock.Unlock() - } - - k.value = v - k.s.keysHash[k.name] = v -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/parser.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/parser.go deleted file mode 100644 index e52ccaee4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/parser.go +++ /dev/null @@ -1,513 +0,0 @@ -// Copyright 2015 Unknwon -// -// 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 ini - -import ( - "bufio" - "bytes" - "fmt" - "io" - "regexp" - "strconv" - "strings" - "unicode" -) - -const minReaderBufferSize = 4096 - -var pythonMultiline = regexp.MustCompile(`^([\t\f ]+)(.*)`) - -type parserOptions struct { - IgnoreContinuation bool - IgnoreInlineComment bool - AllowPythonMultilineValues bool - SpaceBeforeInlineComment bool - UnescapeValueDoubleQuotes bool - UnescapeValueCommentSymbols bool - PreserveSurroundedQuote bool - DebugFunc DebugFunc - ReaderBufferSize int -} - -type parser struct { - buf *bufio.Reader - options parserOptions - - isEOF bool - count int - comment *bytes.Buffer -} - -func (p *parser) debug(format string, args ...interface{}) { - if p.options.DebugFunc != nil { - p.options.DebugFunc(fmt.Sprintf(format, args...)) - } -} - -func newParser(r io.Reader, opts parserOptions) *parser { - size := opts.ReaderBufferSize - if size < minReaderBufferSize { - size = minReaderBufferSize - } - - return &parser{ - buf: bufio.NewReaderSize(r, size), - options: opts, - count: 1, - comment: &bytes.Buffer{}, - } -} - -// BOM handles header of UTF-8, UTF-16 LE and UTF-16 BE's BOM format. -// http://en.wikipedia.org/wiki/Byte_order_mark#Representations_of_byte_order_marks_by_encoding -func (p *parser) BOM() error { - mask, err := p.buf.Peek(2) - if err != nil && err != io.EOF { - return err - } else if len(mask) < 2 { - return nil - } - - switch { - case mask[0] == 254 && mask[1] == 255: - fallthrough - case mask[0] == 255 && mask[1] == 254: - _, err = p.buf.Read(mask) - if err != nil { - return err - } - case mask[0] == 239 && mask[1] == 187: - mask, err := p.buf.Peek(3) - if err != nil && err != io.EOF { - return err - } else if len(mask) < 3 { - return nil - } - if mask[2] == 191 { - _, err = p.buf.Read(mask) - if err != nil { - return err - } - } - } - return nil -} - -func (p *parser) readUntil(delim byte) ([]byte, error) { - data, err := p.buf.ReadBytes(delim) - if err != nil { - if err == io.EOF { - p.isEOF = true - } else { - return nil, err - } - } - return data, nil -} - -func cleanComment(in []byte) ([]byte, bool) { - i := bytes.IndexAny(in, "#;") - if i == -1 { - return nil, false - } - return in[i:], true -} - -func readKeyName(delimiters string, in []byte) (string, int, error) { - line := string(in) - - // Check if key name surrounded by quotes. - var keyQuote string - if line[0] == '"' { - if len(line) > 6 && line[0:3] == `"""` { - keyQuote = `"""` - } else { - keyQuote = `"` - } - } else if line[0] == '`' { - keyQuote = "`" - } - - // Get out key name - var endIdx int - if len(keyQuote) > 0 { - startIdx := len(keyQuote) - // FIXME: fail case -> """"""name"""=value - pos := strings.Index(line[startIdx:], keyQuote) - if pos == -1 { - return "", -1, fmt.Errorf("missing closing key quote: %s", line) - } - pos += startIdx - - // Find key-value delimiter - i := strings.IndexAny(line[pos+startIdx:], delimiters) - if i < 0 { - return "", -1, ErrDelimiterNotFound{line} - } - endIdx = pos + i - return strings.TrimSpace(line[startIdx:pos]), endIdx + startIdx + 1, nil - } - - endIdx = strings.IndexAny(line, delimiters) - if endIdx < 0 { - return "", -1, ErrDelimiterNotFound{line} - } - return strings.TrimSpace(line[0:endIdx]), endIdx + 1, nil -} - -func (p *parser) readMultilines(line, val, valQuote string) (string, error) { - for { - data, err := p.readUntil('\n') - if err != nil { - return "", err - } - next := string(data) - - pos := strings.LastIndex(next, valQuote) - if pos > -1 { - val += next[:pos] - - comment, has := cleanComment([]byte(next[pos:])) - if has { - p.comment.Write(bytes.TrimSpace(comment)) - } - break - } - val += next - if p.isEOF { - return "", fmt.Errorf("missing closing key quote from %q to %q", line, next) - } - } - return val, nil -} - -func (p *parser) readContinuationLines(val string) (string, error) { - for { - data, err := p.readUntil('\n') - if err != nil { - return "", err - } - next := strings.TrimSpace(string(data)) - - if len(next) == 0 { - break - } - val += next - if val[len(val)-1] != '\\' { - break - } - val = val[:len(val)-1] - } - return val, nil -} - -// hasSurroundedQuote check if and only if the first and last characters -// are quotes \" or \'. -// It returns false if any other parts also contain same kind of quotes. -func hasSurroundedQuote(in string, quote byte) bool { - return len(in) >= 2 && in[0] == quote && in[len(in)-1] == quote && - strings.IndexByte(in[1:], quote) == len(in)-2 -} - -func (p *parser) readValue(in []byte, bufferSize int) (string, error) { - - line := strings.TrimLeftFunc(string(in), unicode.IsSpace) - if len(line) == 0 { - if p.options.AllowPythonMultilineValues && len(in) > 0 && in[len(in)-1] == '\n' { - return p.readPythonMultilines(line, bufferSize) - } - return "", nil - } - - var valQuote string - if len(line) > 3 && line[0:3] == `"""` { - valQuote = `"""` - } else if line[0] == '`' { - valQuote = "`" - } else if p.options.UnescapeValueDoubleQuotes && line[0] == '"' { - valQuote = `"` - } - - if len(valQuote) > 0 { - startIdx := len(valQuote) - pos := strings.LastIndex(line[startIdx:], valQuote) - // Check for multi-line value - if pos == -1 { - return p.readMultilines(line, line[startIdx:], valQuote) - } - - if p.options.UnescapeValueDoubleQuotes && valQuote == `"` { - return strings.Replace(line[startIdx:pos+startIdx], `\"`, `"`, -1), nil - } - return line[startIdx : pos+startIdx], nil - } - - lastChar := line[len(line)-1] - // Won't be able to reach here if value only contains whitespace - line = strings.TrimSpace(line) - trimmedLastChar := line[len(line)-1] - - // Check continuation lines when desired - if !p.options.IgnoreContinuation && trimmedLastChar == '\\' { - return p.readContinuationLines(line[:len(line)-1]) - } - - // Check if ignore inline comment - if !p.options.IgnoreInlineComment { - var i int - if p.options.SpaceBeforeInlineComment { - i = strings.Index(line, " #") - if i == -1 { - i = strings.Index(line, " ;") - } - - } else { - i = strings.IndexAny(line, "#;") - } - - if i > -1 { - p.comment.WriteString(line[i:]) - line = strings.TrimSpace(line[:i]) - } - - } - - // Trim single and double quotes - if (hasSurroundedQuote(line, '\'') || - hasSurroundedQuote(line, '"')) && !p.options.PreserveSurroundedQuote { - line = line[1 : len(line)-1] - } else if len(valQuote) == 0 && p.options.UnescapeValueCommentSymbols { - line = strings.ReplaceAll(line, `\;`, ";") - line = strings.ReplaceAll(line, `\#`, "#") - } else if p.options.AllowPythonMultilineValues && lastChar == '\n' { - return p.readPythonMultilines(line, bufferSize) - } - - return line, nil -} - -func (p *parser) readPythonMultilines(line string, bufferSize int) (string, error) { - parserBufferPeekResult, _ := p.buf.Peek(bufferSize) - peekBuffer := bytes.NewBuffer(parserBufferPeekResult) - - for { - peekData, peekErr := peekBuffer.ReadBytes('\n') - if peekErr != nil && peekErr != io.EOF { - p.debug("readPythonMultilines: failed to peek with error: %v", peekErr) - return "", peekErr - } - - p.debug("readPythonMultilines: parsing %q", string(peekData)) - - peekMatches := pythonMultiline.FindStringSubmatch(string(peekData)) - p.debug("readPythonMultilines: matched %d parts", len(peekMatches)) - for n, v := range peekMatches { - p.debug(" %d: %q", n, v) - } - - // Return if not a Python multiline value. - if len(peekMatches) != 3 { - p.debug("readPythonMultilines: end of value, got: %q", line) - return line, nil - } - - // Advance the parser reader (buffer) in-sync with the peek buffer. - _, err := p.buf.Discard(len(peekData)) - if err != nil { - p.debug("readPythonMultilines: failed to skip to the end, returning error") - return "", err - } - - line += "\n" + peekMatches[0] - } -} - -// parse parses data through an io.Reader. -func (f *File) parse(reader io.Reader) (err error) { - p := newParser(reader, parserOptions{ - IgnoreContinuation: f.options.IgnoreContinuation, - IgnoreInlineComment: f.options.IgnoreInlineComment, - AllowPythonMultilineValues: f.options.AllowPythonMultilineValues, - SpaceBeforeInlineComment: f.options.SpaceBeforeInlineComment, - UnescapeValueDoubleQuotes: f.options.UnescapeValueDoubleQuotes, - UnescapeValueCommentSymbols: f.options.UnescapeValueCommentSymbols, - PreserveSurroundedQuote: f.options.PreserveSurroundedQuote, - DebugFunc: f.options.DebugFunc, - ReaderBufferSize: f.options.ReaderBufferSize, - }) - if err = p.BOM(); err != nil { - return fmt.Errorf("BOM: %v", err) - } - - // Ignore error because default section name is never empty string. - name := DefaultSection - if f.options.Insensitive || f.options.InsensitiveSections { - name = strings.ToLower(DefaultSection) - } - section, _ := f.NewSection(name) - - // This "last" is not strictly equivalent to "previous one" if current key is not the first nested key - var isLastValueEmpty bool - var lastRegularKey *Key - - var line []byte - var inUnparseableSection bool - - // NOTE: Iterate and increase `currentPeekSize` until - // the size of the parser buffer is found. - // TODO(unknwon): When Golang 1.10 is the lowest version supported, replace with `parserBufferSize := p.buf.Size()`. - parserBufferSize := 0 - // NOTE: Peek 4kb at a time. - currentPeekSize := minReaderBufferSize - - if f.options.AllowPythonMultilineValues { - for { - peekBytes, _ := p.buf.Peek(currentPeekSize) - peekBytesLength := len(peekBytes) - - if parserBufferSize >= peekBytesLength { - break - } - - currentPeekSize *= 2 - parserBufferSize = peekBytesLength - } - } - - for !p.isEOF { - line, err = p.readUntil('\n') - if err != nil { - return err - } - - if f.options.AllowNestedValues && - isLastValueEmpty && len(line) > 0 { - if line[0] == ' ' || line[0] == '\t' { - err = lastRegularKey.addNestedValue(string(bytes.TrimSpace(line))) - if err != nil { - return err - } - continue - } - } - - line = bytes.TrimLeftFunc(line, unicode.IsSpace) - if len(line) == 0 { - continue - } - - // Comments - if line[0] == '#' || line[0] == ';' { - // Note: we do not care ending line break, - // it is needed for adding second line, - // so just clean it once at the end when set to value. - p.comment.Write(line) - continue - } - - // Section - if line[0] == '[' { - // Read to the next ']' (TODO: support quoted strings) - closeIdx := bytes.LastIndexByte(line, ']') - if closeIdx == -1 { - return fmt.Errorf("unclosed section: %s", line) - } - - name := string(line[1:closeIdx]) - section, err = f.NewSection(name) - if err != nil { - return err - } - - comment, has := cleanComment(line[closeIdx+1:]) - if has { - p.comment.Write(comment) - } - - section.Comment = strings.TrimSpace(p.comment.String()) - - // Reset auto-counter and comments - p.comment.Reset() - p.count = 1 - // Nested values can't span sections - isLastValueEmpty = false - - inUnparseableSection = false - for i := range f.options.UnparseableSections { - if f.options.UnparseableSections[i] == name || - ((f.options.Insensitive || f.options.InsensitiveSections) && strings.EqualFold(f.options.UnparseableSections[i], name)) { - inUnparseableSection = true - continue - } - } - continue - } - - if inUnparseableSection { - section.isRawSection = true - section.rawBody += string(line) - continue - } - - kname, offset, err := readKeyName(f.options.KeyValueDelimiters, line) - if err != nil { - // Treat as boolean key when desired, and whole line is key name. - if IsErrDelimiterNotFound(err) { - switch { - case f.options.AllowBooleanKeys: - kname, err := p.readValue(line, parserBufferSize) - if err != nil { - return err - } - key, err := section.NewBooleanKey(kname) - if err != nil { - return err - } - key.Comment = strings.TrimSpace(p.comment.String()) - p.comment.Reset() - continue - - case f.options.SkipUnrecognizableLines: - continue - } - } - return err - } - - // Auto increment. - isAutoIncr := false - if kname == "-" { - isAutoIncr = true - kname = "#" + strconv.Itoa(p.count) - p.count++ - } - - value, err := p.readValue(line[offset:], parserBufferSize) - if err != nil { - return err - } - isLastValueEmpty = len(value) == 0 - - key, err := section.NewKey(kname, value) - if err != nil { - return err - } - key.isAutoIncrement = isAutoIncr - key.Comment = strings.TrimSpace(p.comment.String()) - p.comment.Reset() - lastRegularKey = key - } - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/section.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/section.go deleted file mode 100644 index dcdb25654..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/section.go +++ /dev/null @@ -1,256 +0,0 @@ -// Copyright 2014 Unknwon -// -// 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 ini - -import ( - "errors" - "fmt" - "strings" -) - -// Section represents a config section. -type Section struct { - f *File - Comment string - name string - keys map[string]*Key - keyList []string - keysHash map[string]string - - isRawSection bool - rawBody string -} - -func newSection(f *File, name string) *Section { - return &Section{ - f: f, - name: name, - keys: make(map[string]*Key), - keyList: make([]string, 0, 10), - keysHash: make(map[string]string), - } -} - -// Name returns name of Section. -func (s *Section) Name() string { - return s.name -} - -// Body returns rawBody of Section if the section was marked as unparseable. -// It still follows the other rules of the INI format surrounding leading/trailing whitespace. -func (s *Section) Body() string { - return strings.TrimSpace(s.rawBody) -} - -// SetBody updates body content only if section is raw. -func (s *Section) SetBody(body string) { - if !s.isRawSection { - return - } - s.rawBody = body -} - -// NewKey creates a new key to given section. -func (s *Section) NewKey(name, val string) (*Key, error) { - if len(name) == 0 { - return nil, errors.New("error creating new key: empty key name") - } else if s.f.options.Insensitive || s.f.options.InsensitiveKeys { - name = strings.ToLower(name) - } - - if s.f.BlockMode { - s.f.lock.Lock() - defer s.f.lock.Unlock() - } - - if inSlice(name, s.keyList) { - if s.f.options.AllowShadows { - if err := s.keys[name].addShadow(val); err != nil { - return nil, err - } - } else { - s.keys[name].value = val - s.keysHash[name] = val - } - return s.keys[name], nil - } - - s.keyList = append(s.keyList, name) - s.keys[name] = newKey(s, name, val) - s.keysHash[name] = val - return s.keys[name], nil -} - -// NewBooleanKey creates a new boolean type key to given section. -func (s *Section) NewBooleanKey(name string) (*Key, error) { - key, err := s.NewKey(name, "true") - if err != nil { - return nil, err - } - - key.isBooleanType = true - return key, nil -} - -// GetKey returns key in section by given name. -func (s *Section) GetKey(name string) (*Key, error) { - if s.f.BlockMode { - s.f.lock.RLock() - } - if s.f.options.Insensitive || s.f.options.InsensitiveKeys { - name = strings.ToLower(name) - } - key := s.keys[name] - if s.f.BlockMode { - s.f.lock.RUnlock() - } - - if key == nil { - // Check if it is a child-section. - sname := s.name - for { - if i := strings.LastIndex(sname, s.f.options.ChildSectionDelimiter); i > -1 { - sname = sname[:i] - sec, err := s.f.GetSection(sname) - if err != nil { - continue - } - return sec.GetKey(name) - } - break - } - return nil, fmt.Errorf("error when getting key of section %q: key %q not exists", s.name, name) - } - return key, nil -} - -// HasKey returns true if section contains a key with given name. -func (s *Section) HasKey(name string) bool { - key, _ := s.GetKey(name) - return key != nil -} - -// Deprecated: Use "HasKey" instead. -func (s *Section) Haskey(name string) bool { - return s.HasKey(name) -} - -// HasValue returns true if section contains given raw value. -func (s *Section) HasValue(value string) bool { - if s.f.BlockMode { - s.f.lock.RLock() - defer s.f.lock.RUnlock() - } - - for _, k := range s.keys { - if value == k.value { - return true - } - } - return false -} - -// Key assumes named Key exists in section and returns a zero-value when not. -func (s *Section) Key(name string) *Key { - key, err := s.GetKey(name) - if err != nil { - // It's OK here because the only possible error is empty key name, - // but if it's empty, this piece of code won't be executed. - key, _ = s.NewKey(name, "") - return key - } - return key -} - -// Keys returns list of keys of section. -func (s *Section) Keys() []*Key { - keys := make([]*Key, len(s.keyList)) - for i := range s.keyList { - keys[i] = s.Key(s.keyList[i]) - } - return keys -} - -// ParentKeys returns list of keys of parent section. -func (s *Section) ParentKeys() []*Key { - var parentKeys []*Key - sname := s.name - for { - if i := strings.LastIndex(sname, s.f.options.ChildSectionDelimiter); i > -1 { - sname = sname[:i] - sec, err := s.f.GetSection(sname) - if err != nil { - continue - } - parentKeys = append(parentKeys, sec.Keys()...) - } else { - break - } - - } - return parentKeys -} - -// KeyStrings returns list of key names of section. -func (s *Section) KeyStrings() []string { - list := make([]string, len(s.keyList)) - copy(list, s.keyList) - return list -} - -// KeysHash returns keys hash consisting of names and values. -func (s *Section) KeysHash() map[string]string { - if s.f.BlockMode { - s.f.lock.RLock() - defer s.f.lock.RUnlock() - } - - hash := make(map[string]string, len(s.keysHash)) - for key, value := range s.keysHash { - hash[key] = value - } - return hash -} - -// DeleteKey deletes a key from section. -func (s *Section) DeleteKey(name string) { - if s.f.BlockMode { - s.f.lock.Lock() - defer s.f.lock.Unlock() - } - - for i, k := range s.keyList { - if k == name { - s.keyList = append(s.keyList[:i], s.keyList[i+1:]...) - delete(s.keys, name) - delete(s.keysHash, name) - return - } - } -} - -// ChildSections returns a list of child sections of current section. -// For example, "[parent.child1]" and "[parent.child12]" are child sections -// of section "[parent]". -func (s *Section) ChildSections() []*Section { - prefix := s.name + s.f.options.ChildSectionDelimiter - children := make([]*Section, 0, 3) - for _, name := range s.f.sectionList { - if strings.HasPrefix(name, prefix) { - children = append(children, s.f.sections[name]...) - } - } - return children -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/struct.go b/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/struct.go deleted file mode 100644 index 6c0924e48..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/ini-main/struct.go +++ /dev/null @@ -1,747 +0,0 @@ -// Copyright 2014 Unknwon -// -// 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 ini - -import ( - "bytes" - "errors" - "fmt" - "reflect" - "strings" - "time" - "unicode" -) - -// NameMapper represents a ini tag name mapper. -type NameMapper func(string) string - -// Built-in name getters. -var ( - // SnackCase converts to format SNACK_CASE. - SnackCase NameMapper = func(raw string) string { - newstr := make([]rune, 0, len(raw)) - for i, chr := range raw { - if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { - if i > 0 { - newstr = append(newstr, '_') - } - } - newstr = append(newstr, unicode.ToUpper(chr)) - } - return string(newstr) - } - // TitleUnderscore converts to format title_underscore. - TitleUnderscore NameMapper = func(raw string) string { - newstr := make([]rune, 0, len(raw)) - for i, chr := range raw { - if isUpper := 'A' <= chr && chr <= 'Z'; isUpper { - if i > 0 { - newstr = append(newstr, '_') - } - chr -= 'A' - 'a' - } - newstr = append(newstr, chr) - } - return string(newstr) - } -) - -func (s *Section) parseFieldName(raw, actual string) string { - if len(actual) > 0 { - return actual - } - if s.f.NameMapper != nil { - return s.f.NameMapper(raw) - } - return raw -} - -func parseDelim(actual string) string { - if len(actual) > 0 { - return actual - } - return "," -} - -var reflectTime = reflect.TypeOf(time.Now()).Kind() - -// setSliceWithProperType sets proper values to slice based on its type. -func setSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { - var strs []string - if allowShadow { - strs = key.StringsWithShadows(delim) - } else { - strs = key.Strings(delim) - } - - numVals := len(strs) - if numVals == 0 { - return nil - } - - var vals interface{} - var err error - - sliceOf := field.Type().Elem().Kind() - switch sliceOf { - case reflect.String: - vals = strs - case reflect.Int: - vals, err = key.parseInts(strs, true, false) - case reflect.Int64: - vals, err = key.parseInt64s(strs, true, false) - case reflect.Uint: - vals, err = key.parseUints(strs, true, false) - case reflect.Uint64: - vals, err = key.parseUint64s(strs, true, false) - case reflect.Float64: - vals, err = key.parseFloat64s(strs, true, false) - case reflect.Bool: - vals, err = key.parseBools(strs, true, false) - case reflectTime: - vals, err = key.parseTimesFormat(time.RFC3339, strs, true, false) - default: - return fmt.Errorf("unsupported type '[]%s'", sliceOf) - } - if err != nil && isStrict { - return err - } - - slice := reflect.MakeSlice(field.Type(), numVals, numVals) - for i := 0; i < numVals; i++ { - switch sliceOf { - case reflect.String: - slice.Index(i).Set(reflect.ValueOf(vals.([]string)[i])) - case reflect.Int: - slice.Index(i).Set(reflect.ValueOf(vals.([]int)[i])) - case reflect.Int64: - slice.Index(i).Set(reflect.ValueOf(vals.([]int64)[i])) - case reflect.Uint: - slice.Index(i).Set(reflect.ValueOf(vals.([]uint)[i])) - case reflect.Uint64: - slice.Index(i).Set(reflect.ValueOf(vals.([]uint64)[i])) - case reflect.Float64: - slice.Index(i).Set(reflect.ValueOf(vals.([]float64)[i])) - case reflect.Bool: - slice.Index(i).Set(reflect.ValueOf(vals.([]bool)[i])) - case reflectTime: - slice.Index(i).Set(reflect.ValueOf(vals.([]time.Time)[i])) - } - } - field.Set(slice) - return nil -} - -func wrapStrictError(err error, isStrict bool) error { - if isStrict { - return err - } - return nil -} - -// setWithProperType sets proper value to field based on its type, -// but it does not return error for failing parsing, -// because we want to use default value that is already assigned to struct. -func setWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow, isStrict bool) error { - vt := t - isPtr := t.Kind() == reflect.Ptr - if isPtr { - vt = t.Elem() - } - switch vt.Kind() { - case reflect.String: - stringVal := key.String() - if isPtr { - field.Set(reflect.ValueOf(&stringVal)) - } else if len(stringVal) > 0 { - field.SetString(key.String()) - } - case reflect.Bool: - boolVal, err := key.Bool() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - field.Set(reflect.ValueOf(&boolVal)) - } else { - field.SetBool(boolVal) - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - // ParseDuration will not return err for `0`, so check the type name - if vt.Name() == "Duration" { - durationVal, err := key.Duration() - if err != nil { - if intVal, err := key.Int64(); err == nil { - field.SetInt(intVal) - return nil - } - return wrapStrictError(err, isStrict) - } - if isPtr { - field.Set(reflect.ValueOf(&durationVal)) - } else if int64(durationVal) > 0 { - field.Set(reflect.ValueOf(durationVal)) - } - return nil - } - - intVal, err := key.Int64() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - pv := reflect.New(t.Elem()) - pv.Elem().SetInt(intVal) - field.Set(pv) - } else { - field.SetInt(intVal) - } - // byte is an alias for uint8, so supporting uint8 breaks support for byte - case reflect.Uint, reflect.Uint16, reflect.Uint32, reflect.Uint64: - durationVal, err := key.Duration() - // Skip zero value - if err == nil && uint64(durationVal) > 0 { - if isPtr { - field.Set(reflect.ValueOf(&durationVal)) - } else { - field.Set(reflect.ValueOf(durationVal)) - } - return nil - } - - uintVal, err := key.Uint64() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - pv := reflect.New(t.Elem()) - pv.Elem().SetUint(uintVal) - field.Set(pv) - } else { - field.SetUint(uintVal) - } - - case reflect.Float32, reflect.Float64: - floatVal, err := key.Float64() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - pv := reflect.New(t.Elem()) - pv.Elem().SetFloat(floatVal) - field.Set(pv) - } else { - field.SetFloat(floatVal) - } - case reflectTime: - timeVal, err := key.Time() - if err != nil { - return wrapStrictError(err, isStrict) - } - if isPtr { - field.Set(reflect.ValueOf(&timeVal)) - } else { - field.Set(reflect.ValueOf(timeVal)) - } - case reflect.Slice: - return setSliceWithProperType(key, field, delim, allowShadow, isStrict) - default: - return fmt.Errorf("unsupported type %q", t) - } - return nil -} - -func parseTagOptions(tag string) (rawName string, omitEmpty bool, allowShadow bool, allowNonUnique bool, extends bool) { - opts := strings.SplitN(tag, ",", 5) - rawName = opts[0] - for _, opt := range opts[1:] { - omitEmpty = omitEmpty || (opt == "omitempty") - allowShadow = allowShadow || (opt == "allowshadow") - allowNonUnique = allowNonUnique || (opt == "nonunique") - extends = extends || (opt == "extends") - } - return rawName, omitEmpty, allowShadow, allowNonUnique, extends -} - -// mapToField maps the given value to the matching field of the given section. -// The sectionIndex is the index (if non unique sections are enabled) to which the value should be added. -func (s *Section) mapToField(val reflect.Value, isStrict bool, sectionIndex int, sectionName string) error { - if val.Kind() == reflect.Ptr { - val = val.Elem() - } - typ := val.Type() - - for i := 0; i < typ.NumField(); i++ { - field := val.Field(i) - tpField := typ.Field(i) - - tag := tpField.Tag.Get("ini") - if tag == "-" { - continue - } - - rawName, _, allowShadow, allowNonUnique, extends := parseTagOptions(tag) - fieldName := s.parseFieldName(tpField.Name, rawName) - if len(fieldName) == 0 || !field.CanSet() { - continue - } - - isStruct := tpField.Type.Kind() == reflect.Struct - isStructPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct - isAnonymousPtr := tpField.Type.Kind() == reflect.Ptr && tpField.Anonymous - if isAnonymousPtr { - field.Set(reflect.New(tpField.Type.Elem())) - } - - if extends && (isAnonymousPtr || (isStruct && tpField.Anonymous)) { - if isStructPtr && field.IsNil() { - field.Set(reflect.New(tpField.Type.Elem())) - } - fieldSection := s - if rawName != "" { - sectionName = s.name + s.f.options.ChildSectionDelimiter + rawName - if secs, err := s.f.SectionsByName(sectionName); err == nil && sectionIndex < len(secs) { - fieldSection = secs[sectionIndex] - } - } - if err := fieldSection.mapToField(field, isStrict, sectionIndex, sectionName); err != nil { - return fmt.Errorf("map to field %q: %v", fieldName, err) - } - } else if isAnonymousPtr || isStruct || isStructPtr { - if secs, err := s.f.SectionsByName(fieldName); err == nil { - if len(secs) <= sectionIndex { - return fmt.Errorf("there are not enough sections (%d <= %d) for the field %q", len(secs), sectionIndex, fieldName) - } - // Only set the field to non-nil struct value if we have a section for it. - // Otherwise, we end up with a non-nil struct ptr even though there is no data. - if isStructPtr && field.IsNil() { - field.Set(reflect.New(tpField.Type.Elem())) - } - if err = secs[sectionIndex].mapToField(field, isStrict, sectionIndex, fieldName); err != nil { - return fmt.Errorf("map to field %q: %v", fieldName, err) - } - continue - } - } - - // Map non-unique sections - if allowNonUnique && tpField.Type.Kind() == reflect.Slice { - newField, err := s.mapToSlice(fieldName, field, isStrict) - if err != nil { - return fmt.Errorf("map to slice %q: %v", fieldName, err) - } - - field.Set(newField) - continue - } - - if key, err := s.GetKey(fieldName); err == nil { - delim := parseDelim(tpField.Tag.Get("delim")) - if err = setWithProperType(tpField.Type, key, field, delim, allowShadow, isStrict); err != nil { - return fmt.Errorf("set field %q: %v", fieldName, err) - } - } - } - return nil -} - -// mapToSlice maps all sections with the same name and returns the new value. -// The type of the Value must be a slice. -func (s *Section) mapToSlice(secName string, val reflect.Value, isStrict bool) (reflect.Value, error) { - secs, err := s.f.SectionsByName(secName) - if err != nil { - return reflect.Value{}, err - } - - typ := val.Type().Elem() - for i, sec := range secs { - elem := reflect.New(typ) - if err = sec.mapToField(elem, isStrict, i, sec.name); err != nil { - return reflect.Value{}, fmt.Errorf("map to field from section %q: %v", secName, err) - } - - val = reflect.Append(val, elem.Elem()) - } - return val, nil -} - -// mapTo maps a section to object v. -func (s *Section) mapTo(v interface{}, isStrict bool) error { - typ := reflect.TypeOf(v) - val := reflect.ValueOf(v) - if typ.Kind() == reflect.Ptr { - typ = typ.Elem() - val = val.Elem() - } else { - return errors.New("not a pointer to a struct") - } - - if typ.Kind() == reflect.Slice { - newField, err := s.mapToSlice(s.name, val, isStrict) - if err != nil { - return err - } - - val.Set(newField) - return nil - } - - return s.mapToField(val, isStrict, 0, s.name) -} - -// MapTo maps section to given struct. -func (s *Section) MapTo(v interface{}) error { - return s.mapTo(v, false) -} - -// StrictMapTo maps section to given struct in strict mode, -// which returns all possible error including value parsing error. -func (s *Section) StrictMapTo(v interface{}) error { - return s.mapTo(v, true) -} - -// MapTo maps file to given struct. -func (f *File) MapTo(v interface{}) error { - return f.Section("").MapTo(v) -} - -// StrictMapTo maps file to given struct in strict mode, -// which returns all possible error including value parsing error. -func (f *File) StrictMapTo(v interface{}) error { - return f.Section("").StrictMapTo(v) -} - -// MapToWithMapper maps data sources to given struct with name mapper. -func MapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { - cfg, err := Load(source, others...) - if err != nil { - return err - } - cfg.NameMapper = mapper - return cfg.MapTo(v) -} - -// StrictMapToWithMapper maps data sources to given struct with name mapper in strict mode, -// which returns all possible error including value parsing error. -func StrictMapToWithMapper(v interface{}, mapper NameMapper, source interface{}, others ...interface{}) error { - cfg, err := Load(source, others...) - if err != nil { - return err - } - cfg.NameMapper = mapper - return cfg.StrictMapTo(v) -} - -// MapTo maps data sources to given struct. -func MapTo(v, source interface{}, others ...interface{}) error { - return MapToWithMapper(v, nil, source, others...) -} - -// StrictMapTo maps data sources to given struct in strict mode, -// which returns all possible error including value parsing error. -func StrictMapTo(v, source interface{}, others ...interface{}) error { - return StrictMapToWithMapper(v, nil, source, others...) -} - -// reflectSliceWithProperType does the opposite thing as setSliceWithProperType. -func reflectSliceWithProperType(key *Key, field reflect.Value, delim string, allowShadow bool) error { - slice := field.Slice(0, field.Len()) - if field.Len() == 0 { - return nil - } - sliceOf := field.Type().Elem().Kind() - - if allowShadow { - var keyWithShadows *Key - for i := 0; i < field.Len(); i++ { - var val string - switch sliceOf { - case reflect.String: - val = slice.Index(i).String() - case reflect.Int, reflect.Int64: - val = fmt.Sprint(slice.Index(i).Int()) - case reflect.Uint, reflect.Uint64: - val = fmt.Sprint(slice.Index(i).Uint()) - case reflect.Float64: - val = fmt.Sprint(slice.Index(i).Float()) - case reflect.Bool: - val = fmt.Sprint(slice.Index(i).Bool()) - case reflectTime: - val = slice.Index(i).Interface().(time.Time).Format(time.RFC3339) - default: - return fmt.Errorf("unsupported type '[]%s'", sliceOf) - } - - if i == 0 { - keyWithShadows = newKey(key.s, key.name, val) - } else { - _ = keyWithShadows.AddShadow(val) - } - } - *key = *keyWithShadows - return nil - } - - var buf bytes.Buffer - for i := 0; i < field.Len(); i++ { - switch sliceOf { - case reflect.String: - buf.WriteString(slice.Index(i).String()) - case reflect.Int, reflect.Int64: - buf.WriteString(fmt.Sprint(slice.Index(i).Int())) - case reflect.Uint, reflect.Uint64: - buf.WriteString(fmt.Sprint(slice.Index(i).Uint())) - case reflect.Float64: - buf.WriteString(fmt.Sprint(slice.Index(i).Float())) - case reflect.Bool: - buf.WriteString(fmt.Sprint(slice.Index(i).Bool())) - case reflectTime: - buf.WriteString(slice.Index(i).Interface().(time.Time).Format(time.RFC3339)) - default: - return fmt.Errorf("unsupported type '[]%s'", sliceOf) - } - buf.WriteString(delim) - } - key.SetValue(buf.String()[:buf.Len()-len(delim)]) - return nil -} - -// reflectWithProperType does the opposite thing as setWithProperType. -func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim string, allowShadow bool) error { - switch t.Kind() { - case reflect.String: - key.SetValue(field.String()) - case reflect.Bool: - key.SetValue(fmt.Sprint(field.Bool())) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - key.SetValue(fmt.Sprint(field.Int())) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - key.SetValue(fmt.Sprint(field.Uint())) - case reflect.Float32, reflect.Float64: - key.SetValue(fmt.Sprint(field.Float())) - case reflectTime: - key.SetValue(fmt.Sprint(field.Interface().(time.Time).Format(time.RFC3339))) - case reflect.Slice: - return reflectSliceWithProperType(key, field, delim, allowShadow) - case reflect.Ptr: - if !field.IsNil() { - return reflectWithProperType(t.Elem(), key, field.Elem(), delim, allowShadow) - } - default: - return fmt.Errorf("unsupported type %q", t) - } - return nil -} - -// CR: copied from encoding/json/encode.go with modifications of time.Time support. -// TODO: add more test coverage. -func isEmptyValue(v reflect.Value) bool { - switch v.Kind() { - case reflect.Array, reflect.Map, reflect.Slice, reflect.String: - return v.Len() == 0 - case reflect.Bool: - return !v.Bool() - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return v.Int() == 0 - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: - return v.Uint() == 0 - case reflect.Float32, reflect.Float64: - return v.Float() == 0 - case reflect.Interface, reflect.Ptr: - return v.IsNil() - case reflectTime: - t, ok := v.Interface().(time.Time) - return ok && t.IsZero() - } - return false -} - -// StructReflector is the interface implemented by struct types that can extract themselves into INI objects. -type StructReflector interface { - ReflectINIStruct(*File) error -} - -func (s *Section) reflectFrom(val reflect.Value) error { - if val.Kind() == reflect.Ptr { - val = val.Elem() - } - typ := val.Type() - - for i := 0; i < typ.NumField(); i++ { - if !val.Field(i).CanInterface() { - continue - } - - field := val.Field(i) - tpField := typ.Field(i) - - tag := tpField.Tag.Get("ini") - if tag == "-" { - continue - } - - rawName, omitEmpty, allowShadow, allowNonUnique, extends := parseTagOptions(tag) - if omitEmpty && isEmptyValue(field) { - continue - } - - if r, ok := field.Interface().(StructReflector); ok { - return r.ReflectINIStruct(s.f) - } - - fieldName := s.parseFieldName(tpField.Name, rawName) - if len(fieldName) == 0 || !field.CanSet() { - continue - } - - if extends && tpField.Anonymous && (tpField.Type.Kind() == reflect.Ptr || tpField.Type.Kind() == reflect.Struct) { - if err := s.reflectFrom(field); err != nil { - return fmt.Errorf("reflect from field %q: %v", fieldName, err) - } - continue - } - - if (tpField.Type.Kind() == reflect.Ptr && tpField.Type.Elem().Kind() == reflect.Struct) || - (tpField.Type.Kind() == reflect.Struct && tpField.Type.Name() != "Time") { - // Note: The only error here is section doesn't exist. - sec, err := s.f.GetSection(fieldName) - if err != nil { - // Note: fieldName can never be empty here, ignore error. - sec, _ = s.f.NewSection(fieldName) - } - - // Add comment from comment tag - if len(sec.Comment) == 0 { - sec.Comment = tpField.Tag.Get("comment") - } - - if err = sec.reflectFrom(field); err != nil { - return fmt.Errorf("reflect from field %q: %v", fieldName, err) - } - continue - } - - if allowNonUnique && tpField.Type.Kind() == reflect.Slice { - slice := field.Slice(0, field.Len()) - if field.Len() == 0 { - return nil - } - sliceOf := field.Type().Elem().Kind() - - for i := 0; i < field.Len(); i++ { - if sliceOf != reflect.Struct && sliceOf != reflect.Ptr { - return fmt.Errorf("field %q is not a slice of pointer or struct", fieldName) - } - - sec, err := s.f.NewSection(fieldName) - if err != nil { - return err - } - - // Add comment from comment tag - if len(sec.Comment) == 0 { - sec.Comment = tpField.Tag.Get("comment") - } - - if err := sec.reflectFrom(slice.Index(i)); err != nil { - return fmt.Errorf("reflect from field %q: %v", fieldName, err) - } - } - continue - } - - // Note: Same reason as section. - key, err := s.GetKey(fieldName) - if err != nil { - key, _ = s.NewKey(fieldName, "") - } - - // Add comment from comment tag - if len(key.Comment) == 0 { - key.Comment = tpField.Tag.Get("comment") - } - - delim := parseDelim(tpField.Tag.Get("delim")) - if err = reflectWithProperType(tpField.Type, key, field, delim, allowShadow); err != nil { - return fmt.Errorf("reflect field %q: %v", fieldName, err) - } - - } - return nil -} - -// ReflectFrom reflects section from given struct. It overwrites existing ones. -func (s *Section) ReflectFrom(v interface{}) error { - typ := reflect.TypeOf(v) - val := reflect.ValueOf(v) - - if s.name != DefaultSection && s.f.options.AllowNonUniqueSections && - (typ.Kind() == reflect.Slice || typ.Kind() == reflect.Ptr) { - // Clear sections to make sure none exists before adding the new ones - s.f.DeleteSection(s.name) - - if typ.Kind() == reflect.Ptr { - sec, err := s.f.NewSection(s.name) - if err != nil { - return err - } - return sec.reflectFrom(val.Elem()) - } - - slice := val.Slice(0, val.Len()) - sliceOf := val.Type().Elem().Kind() - if sliceOf != reflect.Ptr { - return fmt.Errorf("not a slice of pointers") - } - - for i := 0; i < slice.Len(); i++ { - sec, err := s.f.NewSection(s.name) - if err != nil { - return err - } - - err = sec.reflectFrom(slice.Index(i)) - if err != nil { - return fmt.Errorf("reflect from %dth field: %v", i, err) - } - } - - return nil - } - - if typ.Kind() == reflect.Ptr { - val = val.Elem() - } else { - return errors.New("not a pointer to a struct") - } - - return s.reflectFrom(val) -} - -// ReflectFrom reflects file from given struct. -func (f *File) ReflectFrom(v interface{}) error { - return f.Section("").ReflectFrom(v) -} - -// ReflectFromWithMapper reflects data sources from given struct with name mapper. -func ReflectFromWithMapper(cfg *File, v interface{}, mapper NameMapper) error { - cfg.NameMapper = mapper - return cfg.ReflectFrom(v) -} - -// ReflectFrom reflects data sources from given struct. -func ReflectFrom(cfg *File, v interface{}) error { - return ReflectFromWithMapper(cfg, v, nil) -} diff --git a/src/test/regress/go_driver_test/src/github.com/GaussKernel/property.ini b/src/test/regress/go_driver_test/src/github.com/GaussKernel/property.ini deleted file mode 100644 index 21f3ceeb4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/GaussKernel/property.ini +++ /dev/null @@ -1,27 +0,0 @@ -# This file just for local test - -[opengauss] -host=10.244.19.211 -port=5432 -user=gauss -password=Gauss_234 -dbname=gauss -database= -sslmode=require -sslkey= -sslcert= -sslrootcert= -target_session_attrs= -target_server_type= -min_read_buffer_size= -passfile= -connect_timeout= -krbsrvname= -krbspn= -servicefile= -service= -disable_prepared_binary_result= -loggerLevel=trace - - - diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/.circleci/config.yml b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/.circleci/config.yml deleted file mode 100644 index c8f64282e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/.circleci/config.yml +++ /dev/null @@ -1,61 +0,0 @@ -# Golang CircleCI 2.0 configuration file -# -# Check https://circleci.com/docs/2.0/language-go/ for more details -version: 2 -jobs: - build: - docker: - # specify the version - - image: circleci/golang:1.10 - - - image: circleci/mysql:5.7 - environment: - MYSQL_ALLOW_EMPTY_PASSWORD: true - MYSQL_DATABASE: xorm_test - MYSQL_HOST: 127.0.0.1 - MYSQL_ROOT_HOST: '%' - MYSQL_USER: root - - # CircleCI PostgreSQL images available at: https://hub.docker.com/r/circleci/postgres/ - - image: circleci/postgres:9.6.2-alpine - environment: - POSTGRES_USER: circleci - POSTGRES_DB: xorm_test - - - image: microsoft/mssql-server-linux:latest - environment: - ACCEPT_EULA: Y - SA_PASSWORD: yourStrong(!)Password - MSSQL_PID: Developer - - - image: pingcap/tidb:v2.1.2 - - working_directory: /go/src/github.com/go-xorm/xorm - steps: - - checkout - - - run: go get -t -d -v ./... - - run: go get -u xorm.io/core - - run: go get -u xorm.io/builder - - run: GO111MODULE=off go build -v - - run: GO111MODULE=on go build -v - - - run: go get -u github.com/wadey/gocovmerge - - - run: go test -v -race -db="sqlite3" -conn_str="./test.db" -coverprofile=coverage1-1.txt -covermode=atomic - - run: go test -v -race -db="sqlite3" -conn_str="./test.db" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic - - run: go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -coverprofile=coverage2-1.txt -covermode=atomic - - run: go test -v -race -db="mysql" -conn_str="root:@/xorm_test" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic - - run: go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -coverprofile=coverage3-1.txt -covermode=atomic - - run: go test -v -race -db="mymysql" -conn_str="xorm_test/root/" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic - - run: go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -coverprofile=coverage4-1.txt -covermode=atomic - - run: go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic - - run: go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic - - run: go test -v -race -db="postgres" -conn_str="dbname=xorm_test sslmode=disable" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic - - run: go test -v -race -db="mssql" -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" -coverprofile=coverage6-1.txt -covermode=atomic - - run: go test -v -race -db="mssql" -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic - - run: go test -v -race -db="mysql" -conn_str="root:@tcp(localhost:4000)/xorm_test" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic - - run: go test -v -race -db="mysql" -conn_str="root:@tcp(localhost:4000)/xorm_test" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic - - run: gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt - - - run: bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/.drone.yml b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/.drone.yml deleted file mode 100644 index b162d7c8a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/.drone.yml +++ /dev/null @@ -1,823 +0,0 @@ ---- -kind: pipeline -name: matrix-1 - -platform: - os: linux - arch: amd64 - -clone: - disable: true - -workspace: - base: /go - path: src/github.com/go-xorm/xorm - -steps: -- name: git - pull: default - image: plugins/git:next - settings: - depth: 50 - tags: true - -- name: init_postgres - pull: default - image: postgres:9.5 - commands: - - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" - - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" - -- name: build - pull: default - image: golang:1.10 - commands: - - go get -t -d -v ./... - - go get -u xorm.io/core - - go get -u xorm.io/builder - - go build -v - when: - event: - - push - - pull_request - -- name: test-sqlite - pull: default - image: golang:1.10 - commands: - - go get -u github.com/wadey/gocovmerge - - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic" - - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mysql - pull: default - image: golang:1.10 - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mysql-utf8mb4 - pull: default - image: golang:1.10 - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mymysql - pull: default - image: golang:1.10 - commands: - - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic" - - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-postgres - pull: default - image: golang:1.10 - commands: - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic" - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-postgres-schema - pull: default - image: golang:1.10 - commands: - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic" - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mssql - pull: default - image: golang:1.10 - commands: - - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-tidb - pull: default - image: golang:1.10 - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt - when: - event: - - push - - pull_request - -services: -- name: mysql - pull: default - image: mysql:5.7 - environment: - MYSQL_ALLOW_EMPTY_PASSWORD: yes - MYSQL_DATABASE: xorm_test - when: - event: - - push - - tag - - pull_request - -- name: tidb - pull: default - image: pingcap/tidb:v3.0.3 - when: - event: - - push - - tag - - pull_request - -- name: pgsql - pull: default - image: postgres:9.5 - environment: - POSTGRES_DB: xorm_test - POSTGRES_USER: postgres - when: - event: - - push - - tag - - pull_request - -- name: mssql - pull: default - image: microsoft/mssql-server-linux:latest - environment: - ACCEPT_EULA: Y - SA_PASSWORD: yourStrong(!)Password - MSSQL_PID: Developer - when: - event: - - push - - tag - - pull_request - ---- -kind: pipeline -name: matrix-2 - -platform: - os: linux - arch: amd64 - -clone: - disable: true - -workspace: - base: /go - path: src/github.com/go-xorm/xorm - -steps: -- name: git - pull: default - image: plugins/git:next - settings: - depth: 50 - tags: true - -- name: init_postgres - pull: default - image: postgres:9.5 - commands: - - "until psql -U postgres -d xorm_test -h pgsql \\\n -c \"SELECT 1;\" >/dev/null 2>&1; do sleep 1; done\n" - - "psql -U postgres -d xorm_test -h pgsql \\\n -c \"create schema xorm;\"\n" - -- name: build - pull: default - image: golang:1.11 - environment: - GO111MODULE: "off" - commands: - - go get -t -d -v ./... - - go get -u xorm.io/core - - go get -u xorm.io/builder - - go build -v - when: - event: - - push - - pull_request - -- name: build-gomod - pull: default - image: golang:1.11 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - go build -v - when: - event: - - push - - pull_request - -- name: test-sqlite - pull: default - image: golang:1.11 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic" - - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mysql - pull: default - image: golang:1.11 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mysql-utf8mb4 - pull: default - image: golang:1.11 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mymysql - pull: default - image: golang:1.11 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic" - - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-postgres - pull: default - image: golang:1.11 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic" - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-postgres-schema - pull: default - image: golang:1.11 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic" - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mssql - pull: default - image: golang:1.11 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - - when: - event: - - push - - pull_request - -- name: test-tidb - pull: default - image: golang:1.11 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" - - go get github.com/wadey/gocovmerge - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt - when: - event: - - push - - pull_request - -services: -- name: mysql - pull: default - image: mysql:5.7 - environment: - MYSQL_ALLOW_EMPTY_PASSWORD: yes - MYSQL_DATABASE: xorm_test - when: - event: - - push - - tag - - pull_request - -- name: tidb - pull: default - image: pingcap/tidb:v3.0.3 - when: - event: - - push - - tag - - pull_request - -- name: pgsql - pull: default - image: postgres:9.5 - environment: - POSTGRES_DB: xorm_test - POSTGRES_USER: postgres - when: - event: - - push - - tag - - pull_request - -- name: mssql - pull: default - image: microsoft/mssql-server-linux:latest - environment: - ACCEPT_EULA: Y - SA_PASSWORD: yourStrong(!)Password - MSSQL_PID: Developer - when: - event: - - push - - tag - - pull_request - ---- -kind: pipeline -name: matrix-3 - -platform: - os: linux - arch: amd64 - -clone: - disable: true - -workspace: - base: /go - path: src/github.com/go-xorm/xorm - -steps: -- name: git - pull: default - image: plugins/git:next - settings: - depth: 50 - tags: true - -- name: build - pull: default - image: golang:1.12 - environment: - GO111MODULE: "off" - commands: - - go get -t -d -v ./... - - go get -u xorm.io/core - - go get -u xorm.io/builder - - go build -v - when: - event: - - push - - pull_request - -- name: build-gomod - pull: default - image: golang:1.12 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - go build -v - when: - event: - - push - - pull_request - -- name: test-sqlite - pull: default - image: golang:1.12 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic" - - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mysql - pull: default - image: golang:1.12 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mysql-utf8mb4 - pull: default - image: golang:1.12 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mymysql - pull: default - image: golang:1.12 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic" - - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-postgres - pull: default - image: golang:1.12 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic" - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-postgres-schema - pull: default - image: golang:1.12 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic" - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mssql - pull: default - image: golang:1.12 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-tidb - pull: default - image: golang:1.12 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" - - go get github.com/wadey/gocovmerge - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt - when: - event: - - push - - pull_request - -services: -- name: mysql - pull: default - image: mysql:5.7 - environment: - MYSQL_ALLOW_EMPTY_PASSWORD: yes - MYSQL_DATABASE: xorm_test - when: - event: - - push - - tag - - pull_request - -- name: tidb - pull: default - image: pingcap/tidb:v3.0.3 - when: - event: - - push - - tag - - pull_request - -- name: pgsql - pull: default - image: postgres:9.5 - environment: - POSTGRES_DB: xorm_test - POSTGRES_USER: postgres - when: - event: - - push - - tag - - pull_request - -- name: mssql - pull: default - image: microsoft/mssql-server-linux:latest - environment: - ACCEPT_EULA: Y - SA_PASSWORD: yourStrong(!)Password - MSSQL_PID: Developer - when: - event: - - push - - tag - - pull_request - ---- -kind: pipeline -name: go1.13 - -platform: - os: linux - arch: amd64 - -clone: - disable: true - -workspace: - base: /go - path: src/github.com/go-xorm/xorm - -steps: -- name: git - pull: default - image: plugins/git:next - settings: - depth: 50 - tags: true - -- name: build - pull: default - image: golang:1.13 - environment: - GO111MODULE: "off" - commands: - - go get -t -d -v ./... - - go get -u xorm.io/core - - go get -u xorm.io/builder - - go build -v - when: - event: - - push - - pull_request - -- name: build-gomod - pull: default - image: golang:1.13 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - go build -v - when: - event: - - push - - pull_request - -- name: test-sqlite - pull: default - image: golang:1.13 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -coverprofile=coverage1-1.txt -covermode=atomic" - - "go test -v -race -db=\"sqlite3\" -conn_str=\"./test.db\" -cache=true -coverprofile=coverage1-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mysql - pull: default - image: golang:1.13 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -coverprofile=coverage2-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test\" -cache=true -coverprofile=coverage2-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mysql-utf8mb4 - pull: default - image: golang:1.13 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -coverprofile=coverage2.1-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(mysql)/xorm_test?charset=utf8mb4\" -cache=true -coverprofile=coverage2.1-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mymysql - pull: default - image: golang:1.13 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -coverprofile=coverage3-1.txt -covermode=atomic" - - "go test -v -race -db=\"mymysql\" -conn_str=\"tcp:mysql:3306*xorm_test/root/\" -cache=true -coverprofile=coverage3-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-postgres - pull: default - image: golang:1.13 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -coverprofile=coverage4-1.txt -covermode=atomic" - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -cache=true -coverprofile=coverage4-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-postgres-schema - pull: default - image: golang:1.13 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -coverprofile=coverage5-1.txt -covermode=atomic" - - "go test -v -race -db=\"postgres\" -conn_str=\"postgres://postgres:@pgsql/xorm_test?sslmode=disable\" -schema=xorm -cache=true -coverprofile=coverage5-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-mssql - pull: default - image: golang:1.13 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -coverprofile=coverage6-1.txt -covermode=atomic" - - "go test -v -race -db=\"mssql\" -conn_str=\"server=mssql;user id=sa;password=yourStrong(!)Password;database=xorm_test\" -cache=true -coverprofile=coverage6-2.txt -covermode=atomic" - when: - event: - - push - - pull_request - -- name: test-tidb - pull: default - image: golang:1.13 - environment: - GO111MODULE: "on" - GOPROXY: "https://goproxy.cn" - commands: - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -coverprofile=coverage7-1.txt -covermode=atomic" - - "go test -v -race -db=\"mysql\" -conn_str=\"root:@tcp(tidb:4000)/xorm_test\" -ignore_select_update=true -cache=true -coverprofile=coverage7-2.txt -covermode=atomic" - - go get github.com/wadey/gocovmerge - - gocovmerge coverage1-1.txt coverage1-2.txt coverage2-1.txt coverage2-2.txt coverage2.1-1.txt coverage2.1-2.txt coverage3-1.txt coverage3-2.txt coverage4-1.txt coverage4-2.txt coverage5-1.txt coverage5-2.txt coverage6-1.txt coverage6-2.txt coverage7-1.txt coverage7-2.txt > coverage.txt - when: - event: - - push - - pull_request - -services: -- name: mysql - pull: default - image: mysql:5.7 - environment: - MYSQL_ALLOW_EMPTY_PASSWORD: yes - MYSQL_DATABASE: xorm_test - when: - event: - - push - - tag - - pull_request - -- name: tidb - pull: default - image: pingcap/tidb:v3.0.3 - when: - event: - - push - - tag - - pull_request - -- name: pgsql - pull: default - image: postgres:9.5 - environment: - POSTGRES_DB: xorm_test - POSTGRES_USER: postgres - when: - event: - - push - - tag - - pull_request - -- name: mssql - pull: default - image: microsoft/mssql-server-linux:latest - environment: - ACCEPT_EULA: Y - SA_PASSWORD: yourStrong(!)Password - MSSQL_PID: Developer - when: - event: - - push - - tag - - pull_request \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/.gitignore b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/.gitignore deleted file mode 100644 index f1757b983..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/.gitignore +++ /dev/null @@ -1,33 +0,0 @@ -# Compiled Object files, Static and Dynamic libs (Shared Objects) -*.o -*.a -*.so -*.db - -# Folders -_obj -_test - -# Architecture specific extensions/prefixes -*.[568vq] -[568vq].out - -*.cgo1.go -*.cgo2.c -_cgo_defun.c -_cgo_gotypes.go -_cgo_export.* - -_testmain.go - -*.exe - -*.log -.vendor -temp_test.go -.vscode -xorm.test -*.sqlite3 -test.db.sql - -.idea/ diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/CONTRIBUTING.md b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/CONTRIBUTING.md deleted file mode 100644 index 37f4bc5fa..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/CONTRIBUTING.md +++ /dev/null @@ -1,46 +0,0 @@ -## Contributing to xorm - -`xorm` has a backlog of [pull requests](https://help.github.com/articles/using-pull-requests), but contributions are still very -much welcome. You can help with patch review, submitting bug reports, -or adding new functionality. There is no formal style guide, but -please conform to the style of existing code and general Go formatting -conventions when submitting patches. - -* [fork a repo](https://help.github.com/articles/fork-a-repo) -* [creating a pull request ](https://help.github.com/articles/creating-a-pull-request) - -### Language - -Since `xorm` is a world-wide open source project, please describe your issues or code changes in English as soon as possible. - -### Sign your codes with comments -``` -// !! your comments - -e.g., - -// !lunny! this is comments made by lunny -``` - -### Patch review - -Help review existing open [pull requests](https://help.github.com/articles/using-pull-requests) by commenting on the code or -proposed functionality. - -### Bug reports - -We appreciate any bug reports, but especially ones with self-contained -(doesn't depend on code outside of xorm), minimal (can't be simplified -further) test cases. It's especially helpful if you can submit a pull -request with just the failing test case(you can find some example test file like [session_get_test.go](https://github.com/go-xorm/xorm/blob/master/session_get_test.go)). - -If you implements a new database interface, you maybe need to add a test_.sh file. -For example, [mysql_test.go](https://github.com/go-xorm/xorm/blob/master/test_mysql.sh) - -### New functionality - -There are a number of pending patches for new functionality, so -additional feature patches will take a while to merge. Still, patches -are generally reviewed based on usefulness and complexity in addition -to time-in-queue, so if you have a knockout idea, take a shot. Feel -free to open an issue discussion your proposed patch beforehand. diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/LICENSE b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/LICENSE deleted file mode 100644 index 84d2ae538..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/LICENSE +++ /dev/null @@ -1,27 +0,0 @@ -Copyright (c) 2013 - 2015 The Xorm Authors -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -* Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. - -* Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -* Neither the name of the {organization} nor the names of its - contributors may be used to endorse or promote products derived from - this software without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE -FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL -DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR -SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER -CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, -OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE -OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/README.md b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/README.md deleted file mode 100644 index e467f62e0..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/README.md +++ /dev/null @@ -1,503 +0,0 @@ -# xorm HAS BEEN MOVED TO https://gitea.com/xorm/xorm . THIS REPOSITORY WILL NOT BE UPDATED ANY MORE. - -[中文](https://github.com/go-xorm/xorm/blob/master/README_CN.md) - -Xorm is a simple and powerful ORM for Go. - -[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm) -[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm) -[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3) - -## Features - -* Struct <-> Table Mapping Support - -* Chainable APIs - -* Transaction Support - -* Both ORM and raw SQL operation Support - -* Sync database schema Support - -* Query Cache speed up - -* Database Reverse support, See [Xorm Tool README](https://github.com/go-xorm/cmd/blob/master/README.md) - -* Simple cascade loading support - -* Optimistic Locking support - -* SQL Builder support via [xorm.io/builder](https://xorm.io/builder) - -* Automatical Read/Write seperatelly - -* Postgres schema support - -* Context Cache support - -## Drivers Support - -Drivers for Go's sql package which currently support database/sql includes: - -* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) - -* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/tree/master/godrv) - -* Postgres: [github.com/lib/pq](https://github.com/lib/pq) - -* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb) - -* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - -* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) - -* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (experiment) - -## Installation - - go get github.com/go-xorm/xorm - -## Documents - -* [Manual](http://xorm.io/docs) - -* [GoDoc](http://godoc.org/github.com/go-xorm/xorm) - -## Quick Start - -* Create Engine - -```Go -engine, err := xorm.NewEngine(driverName, dataSourceName) -``` - -* Define a struct and Sync2 table struct to database - -```Go -type User struct { - Id int64 - Name string - Salt string - Age int - Passwd string `xorm:"varchar(200)"` - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` -} - -err := engine.Sync2(new(User)) -``` - -* Create Engine Group - -```Go -dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName} -engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice) -``` - -```Go -masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName) -slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName) -slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName) -engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine}) -``` - -Then all place where `engine` you can just use `engineGroup`. - -* `Query` runs a SQL string, the returned results is `[]map[string][]byte`, `QueryString` returns `[]map[string]string`, `QueryInterface` returns `[]map[string]interface{}`. - -```Go -results, err := engine.Query("select * from user") -results, err := engine.Where("a = 1").Query() - -results, err := engine.QueryString("select * from user") -results, err := engine.Where("a = 1").QueryString() - -results, err := engine.QueryInterface("select * from user") -results, err := engine.Where("a = 1").QueryInterface() -``` - -* `Exec` runs a SQL string, it returns `affected` and `error` - -```Go -affected, err := engine.Exec("update user set age = ? where name = ?", age, name) -``` - -* `Insert` one or multiple records to database - -```Go -affected, err := engine.Insert(&user) -// INSERT INTO struct () values () - -affected, err := engine.Insert(&user1, &user2) -// INSERT INTO struct1 () values () -// INSERT INTO struct2 () values () - -affected, err := engine.Insert(&users) -// INSERT INTO struct () values (),(),() - -affected, err := engine.Insert(&user1, &users) -// INSERT INTO struct1 () values () -// INSERT INTO struct2 () values (),(),() -``` - -* `Get` query one record from database - -```Go -has, err := engine.Get(&user) -// SELECT * FROM user LIMIT 1 - -has, err := engine.Where("name = ?", name).Desc("id").Get(&user) -// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1 - -var name string -has, err := engine.Table(&user).Where("id = ?", id).Cols("name").Get(&name) -// SELECT name FROM user WHERE id = ? - -var id int64 -has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id) -has, err := engine.SQL("select id from user").Get(&id) -// SELECT id FROM user WHERE name = ? - -var valuesMap = make(map[string]string) -has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap) -// SELECT * FROM user WHERE id = ? - -var valuesSlice = make([]interface{}, len(cols)) -has, err := engine.Table(&user).Where("id = ?", id).Cols(cols...).Get(&valuesSlice) -// SELECT col1, col2, col3 FROM user WHERE id = ? -``` - -* `Exist` check if one record exist on table - -```Go -has, err := testEngine.Exist(new(RecordExist)) -// SELECT * FROM record_exist LIMIT 1 - -has, err = testEngine.Exist(&RecordExist{ - Name: "test1", - }) -// SELECT * FROM record_exist WHERE name = ? LIMIT 1 - -has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{}) -// SELECT * FROM record_exist WHERE name = ? LIMIT 1 - -has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist() -// select * from record_exist where name = ? - -has, err = testEngine.Table("record_exist").Exist() -// SELECT * FROM record_exist LIMIT 1 - -has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist() -// SELECT * FROM record_exist WHERE name = ? LIMIT 1 -``` - -* `Find` query multiple records from database, also you can use join and extends - -```Go -var users []User -err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users) -// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0 - -type Detail struct { - Id int64 - UserId int64 `xorm:"index"` -} - -type UserDetail struct { - User `xorm:"extends"` - Detail `xorm:"extends"` -} - -var users []UserDetail -err := engine.Table("user").Select("user.*, detail.*"). - Join("INNER", "detail", "detail.user_id = user.id"). - Where("user.name = ?", name).Limit(10, 0). - Find(&users) -// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0 -``` - -* `Iterate` and `Rows` query multiple records and record by record handle, there are two methods Iterate and Rows - -```Go -err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error { - user := bean.(*User) - return nil -}) -// SELECT * FROM user - -err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error { - user := bean.(*User) - return nil -}) -// SELECT * FROM user Limit 0, 100 -// SELECT * FROM user Limit 101, 100 - -rows, err := engine.Rows(&User{Name:name}) -// SELECT * FROM user -defer rows.Close() -bean := new(Struct) -for rows.Next() { - err = rows.Scan(bean) -} -``` - -* `Update` update one or more records, default will update non-empty and non-zero fields except when you use Cols, AllCols and so on. - -```Go -affected, err := engine.ID(1).Update(&user) -// UPDATE user SET ... Where id = ? - -affected, err := engine.Update(&user, &User{Name:name}) -// UPDATE user SET ... Where name = ? - -var ids = []int64{1, 2, 3} -affected, err := engine.In("id", ids).Update(&user) -// UPDATE user SET ... Where id IN (?, ?, ?) - -// force update indicated columns by Cols -affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12}) -// UPDATE user SET age = ?, updated=? Where id = ? - -// force NOT update indicated columns by Omit -affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12}) -// UPDATE user SET age = ?, updated=? Where id = ? - -affected, err := engine.ID(1).AllCols().Update(&user) -// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ? -``` - -* `Delete` delete one or more records, Delete MUST have condition - -```Go -affected, err := engine.Where(...).Delete(&user) -// DELETE FROM user Where ... - -affected, err := engine.ID(2).Delete(&user) -// DELETE FROM user Where id = ? -``` - -* `Count` count records - -```Go -counts, err := engine.Count(&user) -// SELECT count(*) AS total FROM user -``` - -* `FindAndCount` combines function `Find` with `Count` which is usually used in query by page - -```Go -var users []User -counts, err := engine.FindAndCount(&users) -``` - -* `Sum` sum functions - -```Go -agesFloat64, err := engine.Sum(&user, "age") -// SELECT sum(age) AS total FROM user - -agesInt64, err := engine.SumInt(&user, "age") -// SELECT sum(age) AS total FROM user - -sumFloat64Slice, err := engine.Sums(&user, "age", "score") -// SELECT sum(age), sum(score) FROM user - -sumInt64Slice, err := engine.SumsInt(&user, "age", "score") -// SELECT sum(age), sum(score) FROM user -``` - -* Query conditions builder - -```Go -err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users) -// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?) -``` - -* Multiple operations in one go routine, no transation here but resue session memory - -```Go -session := engine.NewSession() -defer session.Close() - -user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} -if _, err := session.Insert(&user1); err != nil { - return err -} - -user2 := Userinfo{Username: "yyy"} -if _, err := session.Where("id = ?", 2).Update(&user2); err != nil { - return err -} - -if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil { - return err -} - -return nil -``` - -* Transation should on one go routine. There is transaction and resue session memory - -```Go -session := engine.NewSession() -defer session.Close() - -// add Begin() before any action -if err := session.Begin(); err != nil { - // if returned then will rollback automatically - return err -} - -user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} -if _, err := session.Insert(&user1); err != nil { - return err -} - -user2 := Userinfo{Username: "yyy"} -if _, err := session.Where("id = ?", 2).Update(&user2); err != nil { - return err -} - -if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil { - return err -} - -// add Commit() after all actions -return session.Commit() -``` - -* Or you can use `Transaction` to replace above codes. - -```Go -res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) { - user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} - if _, err := session.Insert(&user1); err != nil { - return nil, err - } - - user2 := Userinfo{Username: "yyy"} - if _, err := session.Where("id = ?", 2).Update(&user2); err != nil { - return nil, err - } - - if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil { - return nil, err - } - return nil, nil -}) -``` - -* Context Cache, if enabled, current query result will be cached on session and be used by next same statement on the same session. - -```Go - sess := engine.NewSession() - defer sess.Close() - - var context = xorm.NewMemoryContextCache() - - var c2 ContextGetStruct - has, err := sess.ID(1).ContextCache(context).Get(&c2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, 1, c2.Id) - assert.EqualValues(t, "1", c2.Name) - sql, args := sess.LastSQL() - assert.True(t, len(sql) > 0) - assert.True(t, len(args) > 0) - - var c3 ContextGetStruct - has, err = sess.ID(1).ContextCache(context).Get(&c3) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, 1, c3.Id) - assert.EqualValues(t, "1", c3.Name) - sql, args = sess.LastSQL() - assert.True(t, len(sql) == 0) - assert.True(t, len(args) == 0) -``` - -## Contributing - -If you want to pull request, please see [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md). And we also provide [Xorm on Google Groups](https://groups.google.com/forum/#!forum/xorm) to discuss. - -## Credits - -### Contributors - -This project exists thanks to all the people who contribute. [[Contribute](CONTRIBUTING.md)]. - - -### Backers - -Thank you to all our backers! 🙏 [[Become a backer](https://opencollective.com/xorm#backer)] - - - -### Sponsors - -Support this project by becoming a sponsor. Your logo will show up here with a link to your website. [[Become a sponsor](https://opencollective.com/xorm#sponsor)] - -## Changelog - -* **v0.7.0** - * Some bugs fixed - -* **v0.6.6** - * Some bugs fixed - -* **v0.6.5** - * Postgres schema support - * vgo support - * Add FindAndCount - * Database special params support via NewEngineWithParams - * Some bugs fixed - -* **v0.6.4** - * Automatical Read/Write seperatelly - * Query/QueryString/QueryInterface and action with Where/And - * Get support non-struct variables - * BufferSize on Iterate - * fix some other bugs. - -[More changes ...](https://github.com/go-xorm/manual-en-US/tree/master/chapter-16) - -## Cases - -* [studygolang](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang) - -* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea) - -* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs) - -* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana) - -* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader) - -* [Wego](http://github.com/go-tango/wego) - -* [Docker.cn](https://docker.cn/) - -* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter) - -* [Gorevel](http://gorevel.cn/) - [github.com/goofcc/gorevel](http://github.com/goofcc/gorevel) - -* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) - -* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild) - -* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress) - -* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily) - -* [YouGam](http://www.yougam.com/) - -* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS) - -* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/) - -* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog) - -## LICENSE - -BSD License [http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/) diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/README_CN.md b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/README_CN.md deleted file mode 100644 index 0cec6ed5c..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/README_CN.md +++ /dev/null @@ -1,500 +0,0 @@ -# xorm - -[English](https://github.com/go-xorm/xorm/blob/master/README.md) - -xorm是一个简单而强大的Go语言ORM库. 通过它可以使数据库操作非常简便。 - -[![CircleCI](https://circleci.com/gh/go-xorm/xorm.svg?style=shield)](https://circleci.com/gh/go-xorm/xorm) [![codecov](https://codecov.io/gh/go-xorm/xorm/branch/master/graph/badge.svg)](https://codecov.io/gh/go-xorm/xorm) -[![](https://goreportcard.com/badge/github.com/go-xorm/xorm)](https://goreportcard.com/report/github.com/go-xorm/xorm) -[![Join the chat at https://img.shields.io/discord/323460943201959939.svg](https://img.shields.io/discord/323460943201959939.svg)](https://discord.gg/HuR2CF3) - -## 特性 - -* 支持Struct和数据库表之间的灵活映射,并支持自动同步 - -* 事务支持 - -* 同时支持原始SQL语句和ORM操作的混合执行 - -* 使用连写来简化调用 - -* 支持使用Id, In, Where, Limit, Join, Having, Table, Sql, Cols等函数和结构体等方式作为条件 - -* 支持级联加载Struct - -* Schema支持(仅Postgres) - -* 支持缓存 - -* 支持根据数据库自动生成xorm的结构体 - -* 支持记录版本(即乐观锁) - -* 内置SQL Builder支持 - -* 上下文缓存支持 - -## 驱动支持 - -目前支持的Go数据库驱动和对应的数据库如下: - -* Mysql: [github.com/go-sql-driver/mysql](https://github.com/go-sql-driver/mysql) - -* MyMysql: [github.com/ziutek/mymysql/godrv](https://github.com/ziutek/mymysql/godrv) - -* Postgres: [github.com/lib/pq](https://github.com/lib/pq) - -* Tidb: [github.com/pingcap/tidb](https://github.com/pingcap/tidb) - -* SQLite: [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3) - -* MsSql: [github.com/denisenkom/go-mssqldb](https://github.com/denisenkom/go-mssqldb) - -* MsSql: [github.com/lunny/godbc](https://github.com/lunny/godbc) - -* Oracle: [github.com/mattn/go-oci8](https://github.com/mattn/go-oci8) (试验性支持) - -## 安装 - - go get github.com/go-xorm/xorm - -## 文档 - -* [操作指南](http://xorm.io/docs) - -* [GoWalker代码文档](http://gowalker.org/github.com/go-xorm/xorm) - -* [Godoc代码文档](http://godoc.org/github.com/go-xorm/xorm) - -# 快速开始 - -* 第一步创建引擎,driverName, dataSourceName和database/sql接口相同 - -```Go -engine, err := xorm.NewEngine(driverName, dataSourceName) -``` - -* 定义一个和表同步的结构体,并且自动同步结构体到数据库 - -```Go -type User struct { - Id int64 - Name string - Salt string - Age int - Passwd string `xorm:"varchar(200)"` - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` -} - -err := engine.Sync2(new(User)) -``` - -* 创建Engine组 - -```Go -dataSourceNameSlice := []string{masterDataSourceName, slave1DataSourceName, slave2DataSourceName} -engineGroup, err := xorm.NewEngineGroup(driverName, dataSourceNameSlice) -``` - -```Go -masterEngine, err := xorm.NewEngine(driverName, masterDataSourceName) -slave1Engine, err := xorm.NewEngine(driverName, slave1DataSourceName) -slave2Engine, err := xorm.NewEngine(driverName, slave2DataSourceName) -engineGroup, err := xorm.NewEngineGroup(masterEngine, []*Engine{slave1Engine, slave2Engine}) -``` - -所有使用 `engine` 都可以简单的用 `engineGroup` 来替换。 - -* `Query` 最原始的也支持SQL语句查询,返回的结果类型为 []map[string][]byte。`QueryString` 返回 []map[string]string, `QueryInterface` 返回 `[]map[string]interface{}`. - -```Go -results, err := engine.Query("select * from user") -results, err := engine.Where("a = 1").Query() - -results, err := engine.QueryString("select * from user") -results, err := engine.Where("a = 1").QueryString() - -results, err := engine.QueryInterface("select * from user") -results, err := engine.Where("a = 1").QueryInterface() -``` - -* `Exec` 执行一个SQL语句 - -```Go -affected, err := engine.Exec("update user set age = ? where name = ?", age, name) -``` - -* `Insert` 插入一条或者多条记录 - -```Go -affected, err := engine.Insert(&user) -// INSERT INTO struct () values () - -affected, err := engine.Insert(&user1, &user2) -// INSERT INTO struct1 () values () -// INSERT INTO struct2 () values () - -affected, err := engine.Insert(&users) -// INSERT INTO struct () values (),(),() - -affected, err := engine.Insert(&user1, &users) -// INSERT INTO struct1 () values () -// INSERT INTO struct2 () values (),(),() -``` - -* `Get` 查询单条记录 - -```Go -has, err := engine.Get(&user) -// SELECT * FROM user LIMIT 1 - -has, err := engine.Where("name = ?", name).Desc("id").Get(&user) -// SELECT * FROM user WHERE name = ? ORDER BY id DESC LIMIT 1 - -var name string -has, err := engine.Table(&user).Where("id = ?", id).Cols("name").Get(&name) -// SELECT name FROM user WHERE id = ? - -var id int64 -has, err := engine.Table(&user).Where("name = ?", name).Cols("id").Get(&id) -has, err := engine.SQL("select id from user").Get(&id) -// SELECT id FROM user WHERE name = ? - -var valuesMap = make(map[string]string) -has, err := engine.Table(&user).Where("id = ?", id).Get(&valuesMap) -// SELECT * FROM user WHERE id = ? - -var valuesSlice = make([]interface{}, len(cols)) -has, err := engine.Table(&user).Where("id = ?", id).Cols(cols...).Get(&valuesSlice) -// SELECT col1, col2, col3 FROM user WHERE id = ? -``` - -* `Exist` 检测记录是否存在 - -```Go -has, err := testEngine.Exist(new(RecordExist)) -// SELECT * FROM record_exist LIMIT 1 - -has, err = testEngine.Exist(&RecordExist{ - Name: "test1", - }) -// SELECT * FROM record_exist WHERE name = ? LIMIT 1 - -has, err = testEngine.Where("name = ?", "test1").Exist(&RecordExist{}) -// SELECT * FROM record_exist WHERE name = ? LIMIT 1 - -has, err = testEngine.SQL("select * from record_exist where name = ?", "test1").Exist() -// select * from record_exist where name = ? - -has, err = testEngine.Table("record_exist").Exist() -// SELECT * FROM record_exist LIMIT 1 - -has, err = testEngine.Table("record_exist").Where("name = ?", "test1").Exist() -// SELECT * FROM record_exist WHERE name = ? LIMIT 1 -``` - -* `Find` 查询多条记录,当然可以使用Join和extends来组合使用 - -```Go -var users []User -err := engine.Where("name = ?", name).And("age > 10").Limit(10, 0).Find(&users) -// SELECT * FROM user WHERE name = ? AND age > 10 limit 10 offset 0 - -type Detail struct { - Id int64 - UserId int64 `xorm:"index"` -} - -type UserDetail struct { - User `xorm:"extends"` - Detail `xorm:"extends"` -} - -var users []UserDetail -err := engine.Table("user").Select("user.*, detail.*") - Join("INNER", "detail", "detail.user_id = user.id"). - Where("user.name = ?", name).Limit(10, 0). - Find(&users) -// SELECT user.*, detail.* FROM user INNER JOIN detail WHERE user.name = ? limit 10 offset 0 -``` - -* `Iterate` 和 `Rows` 根据条件遍历数据库,可以有两种方式: Iterate and Rows - -```Go -err := engine.Iterate(&User{Name:name}, func(idx int, bean interface{}) error { - user := bean.(*User) - return nil -}) -// SELECT * FROM user - -err := engine.BufferSize(100).Iterate(&User{Name:name}, func(idx int, bean interface{}) error { - user := bean.(*User) - return nil -}) -// SELECT * FROM user Limit 0, 100 -// SELECT * FROM user Limit 101, 100 - -rows, err := engine.Rows(&User{Name:name}) -// SELECT * FROM user -defer rows.Close() -bean := new(Struct) -for rows.Next() { - err = rows.Scan(bean) -} -``` - -* `Update` 更新数据,除非使用Cols,AllCols函数指明,默认只更新非空和非0的字段 - -```Go -affected, err := engine.ID(1).Update(&user) -// UPDATE user SET ... Where id = ? - -affected, err := engine.Update(&user, &User{Name:name}) -// UPDATE user SET ... Where name = ? - -var ids = []int64{1, 2, 3} -affected, err := engine.In(ids).Update(&user) -// UPDATE user SET ... Where id IN (?, ?, ?) - -// force update indicated columns by Cols -affected, err := engine.ID(1).Cols("age").Update(&User{Name:name, Age: 12}) -// UPDATE user SET age = ?, updated=? Where id = ? - -// force NOT update indicated columns by Omit -affected, err := engine.ID(1).Omit("name").Update(&User{Name:name, Age: 12}) -// UPDATE user SET age = ?, updated=? Where id = ? - -affected, err := engine.ID(1).AllCols().Update(&user) -// UPDATE user SET name=?,age=?,salt=?,passwd=?,updated=? Where id = ? -``` - -* `Delete` 删除记录,需要注意,删除必须至少有一个条件,否则会报错。要清空数据库可以用EmptyTable - -```Go -affected, err := engine.Where(...).Delete(&user) -// DELETE FROM user Where ... - -affected, err := engine.ID(2).Delete(&user) -// DELETE FROM user Where id = ? -``` - -* `Count` 获取记录条数 - -```Go -counts, err := engine.Count(&user) -// SELECT count(*) AS total FROM user -``` - -* `Sum` 求和函数 - -```Go -agesFloat64, err := engine.Sum(&user, "age") -// SELECT sum(age) AS total FROM user - -agesInt64, err := engine.SumInt(&user, "age") -// SELECT sum(age) AS total FROM user - -sumFloat64Slice, err := engine.Sums(&user, "age", "score") -// SELECT sum(age), sum(score) FROM user - -sumInt64Slice, err := engine.SumsInt(&user, "age", "score") -// SELECT sum(age), sum(score) FROM user -``` - -* 条件编辑器 - -```Go -err := engine.Where(builder.NotIn("a", 1, 2).And(builder.In("b", "c", "d", "e"))).Find(&users) -// SELECT id, name ... FROM user WHERE a NOT IN (?, ?) AND b IN (?, ?, ?) -``` - -* 在一个Go程中多次操作数据库,但没有事务 - -```Go -session := engine.NewSession() -defer session.Close() - -user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} -if _, err := session.Insert(&user1); err != nil { - return err -} - -user2 := Userinfo{Username: "yyy"} -if _, err := session.Where("id = ?", 2).Update(&user2); err != nil { - return err -} - -if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil { - return err -} - -return nil -``` - -* 在一个Go程中有事务 - -```Go -session := engine.NewSession() -defer session.Close() - -// add Begin() before any action -if err := session.Begin(); err != nil { - // if returned then will rollback automatically - return err -} - -user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} -if _, err := session.Insert(&user1); err != nil { - return err -} - -user2 := Userinfo{Username: "yyy"} -if _, err := session.Where("id = ?", 2).Update(&user2); err != nil { - return err -} - -if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil { - return err -} - -// add Commit() after all actions -return session.Commit() -``` - -* 事务的简写方法 - -```Go -res, err := engine.Transaction(func(session *xorm.Session) (interface{}, error) { - user1 := Userinfo{Username: "xiaoxiao", Departname: "dev", Alias: "lunny", Created: time.Now()} - if _, err := session.Insert(&user1); err != nil { - return nil, err - } - - user2 := Userinfo{Username: "yyy"} - if _, err := session.Where("id = ?", 2).Update(&user2); err != nil { - return nil, err - } - - if _, err := session.Exec("delete from userinfo where username = ?", user2.Username); err != nil { - return nil, err - } - return nil, nil -}) -``` - -* 上下文缓存,如果启用,那么针对单个对象的查询将会被缓存到系统中,可以被下一个查询使用。 - -```Go - sess := engine.NewSession() - defer sess.Close() - - var context = xorm.NewMemoryContextCache() - - var c2 ContextGetStruct - has, err := sess.ID(1).ContextCache(context).Get(&c2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, 1, c2.Id) - assert.EqualValues(t, "1", c2.Name) - sql, args := sess.LastSQL() - assert.True(t, len(sql) > 0) - assert.True(t, len(args) > 0) - - var c3 ContextGetStruct - has, err = sess.ID(1).ContextCache(context).Get(&c3) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, 1, c3.Id) - assert.EqualValues(t, "1", c3.Name) - sql, args = sess.LastSQL() - assert.True(t, len(sql) == 0) - assert.True(t, len(args) == 0) -``` - -## 贡献 - -如果您也想为Xorm贡献您的力量,请查看 [CONTRIBUTING](https://github.com/go-xorm/xorm/blob/master/CONTRIBUTING.md)。您也可以加入QQ群 技术帮助和讨论。 -群一:280360085 (已满) -群二:795010183 - -## Credits - -### Contributors - -感谢所有的贡献者. [[Contribute](CONTRIBUTING.md)]. - - -### Backers - -感谢我们所有的 backers! 🙏 [[成为 backer](https://opencollective.com/xorm#backer)] - - - -### Sponsors - -成为 sponsor 来支持 xorm。您的 logo 将会被显示并被链接到您的网站。 [[成为 sponsor](https://opencollective.com/xorm#sponsor)] - -# 案例 - -* [Go语言中文网](http://studygolang.com/) - [github.com/studygolang/studygolang](https://github.com/studygolang/studygolang) - -* [Gitea](http://gitea.io) - [github.com/go-gitea/gitea](http://github.com/go-gitea/gitea) - -* [Gogs](http://try.gogits.org) - [github.com/gogits/gogs](http://github.com/gogits/gogs) - -* [grafana](https://grafana.com/) - [github.com/grafana/grafana](http://github.com/grafana/grafana) - -* [github.com/m3ng9i/qreader](https://github.com/m3ng9i/qreader) - -* [Wego](http://github.com/go-tango/wego) - -* [Docker.cn](https://docker.cn/) - -* [Xorm Adapter](https://github.com/casbin/xorm-adapter) for [Casbin](https://github.com/casbin/casbin) - [github.com/casbin/xorm-adapter](https://github.com/casbin/xorm-adapter) - -* [Gowalker](http://gowalker.org) - [github.com/Unknwon/gowalker](http://github.com/Unknwon/gowalker) - -* [Gobuild.io](http://gobuild.io) - [github.com/shxsun/gobuild](http://github.com/shxsun/gobuild) - -* [Sudo China](http://sudochina.com) - [github.com/insionng/toropress](http://github.com/insionng/toropress) - -* [Godaily](http://godaily.org) - [github.com/govc/godaily](http://github.com/govc/godaily) - -* [YouGam](http://www.yougam.com/) - -* [GoCMS - github.com/zzboy/GoCMS](https://github.com/zzdboy/GoCMS) - -* [GoBBS - gobbs.domolo.com](http://gobbs.domolo.com/) - -* [go-blog](http://wangcheng.me) - [github.com/easykoo/go-blog](https://github.com/easykoo/go-blog) - - -## 更新日志 - -* **v0.7.0** - * 修正部分Bug - -* **v0.6.6** - * 修正部分Bug - -* **v0.6.5** - * 通过 engine.SetSchema 来支持 schema,当前仅支持Postgres - * vgo 支持 - * 新增 `FindAndCount` 函数 - * 通过 `NewEngineWithParams` 支持数据库特别参数 - * 修正部分Bug - -* **v0.6.4** - * 自动读写分离支持 - * Query/QueryString/QueryInterface 支持与 Where/And 合用 - * `Get` 支持获取非结构体变量 - * `Iterate` 支持 `BufferSize` - * 修正部分Bug - -[更多更新日志...](https://github.com/go-xorm/manual-zh-CN/tree/master/chapter-16) - -## LICENSE - -BSD License -[http://creativecommons.org/licenses/BSD/](http://creativecommons.org/licenses/BSD/) diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/cache_lru.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/cache_lru.go deleted file mode 100644 index ab948bd28..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/cache_lru.go +++ /dev/null @@ -1,284 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "container/list" - "fmt" - "sync" - "time" - - "xorm.io/core" -) - -// LRUCacher implments cache object facilities -type LRUCacher struct { - idList *list.List - sqlList *list.List - idIndex map[string]map[string]*list.Element - sqlIndex map[string]map[string]*list.Element - store core.CacheStore - mutex sync.Mutex - MaxElementSize int - Expired time.Duration - GcInterval time.Duration -} - -// NewLRUCacher creates a cacher -func NewLRUCacher(store core.CacheStore, maxElementSize int) *LRUCacher { - return NewLRUCacher2(store, 3600*time.Second, maxElementSize) -} - -// NewLRUCacher2 creates a cache include different params -func NewLRUCacher2(store core.CacheStore, expired time.Duration, maxElementSize int) *LRUCacher { - cacher := &LRUCacher{store: store, idList: list.New(), - sqlList: list.New(), Expired: expired, - GcInterval: core.CacheGcInterval, MaxElementSize: maxElementSize, - sqlIndex: make(map[string]map[string]*list.Element), - idIndex: make(map[string]map[string]*list.Element), - } - cacher.RunGC() - return cacher -} - -// RunGC run once every m.GcInterval -func (m *LRUCacher) RunGC() { - time.AfterFunc(m.GcInterval, func() { - m.RunGC() - m.GC() - }) -} - -// GC check ids lit and sql list to remove all element expired -func (m *LRUCacher) GC() { - m.mutex.Lock() - defer m.mutex.Unlock() - var removedNum int - for e := m.idList.Front(); e != nil; { - if removedNum <= core.CacheGcMaxRemoved && - time.Now().Sub(e.Value.(*idNode).lastVisit) > m.Expired { - removedNum++ - next := e.Next() - node := e.Value.(*idNode) - m.delBean(node.tbName, node.id) - e = next - } else { - break - } - } - - removedNum = 0 - for e := m.sqlList.Front(); e != nil; { - if removedNum <= core.CacheGcMaxRemoved && - time.Now().Sub(e.Value.(*sqlNode).lastVisit) > m.Expired { - removedNum++ - next := e.Next() - node := e.Value.(*sqlNode) - m.delIds(node.tbName, node.sql) - e = next - } else { - break - } - } -} - -// GetIds returns all bean's ids according to sql and parameter from cache -func (m *LRUCacher) GetIds(tableName, sql string) interface{} { - m.mutex.Lock() - defer m.mutex.Unlock() - if _, ok := m.sqlIndex[tableName]; !ok { - m.sqlIndex[tableName] = make(map[string]*list.Element) - } - if v, err := m.store.Get(sql); err == nil { - if el, ok := m.sqlIndex[tableName][sql]; !ok { - el = m.sqlList.PushBack(newSQLNode(tableName, sql)) - m.sqlIndex[tableName][sql] = el - } else { - lastTime := el.Value.(*sqlNode).lastVisit - // if expired, remove the node and return nil - if time.Now().Sub(lastTime) > m.Expired { - m.delIds(tableName, sql) - return nil - } - m.sqlList.MoveToBack(el) - el.Value.(*sqlNode).lastVisit = time.Now() - } - return v - } - - m.delIds(tableName, sql) - return nil -} - -// GetBean returns bean according tableName and id from cache -func (m *LRUCacher) GetBean(tableName string, id string) interface{} { - m.mutex.Lock() - defer m.mutex.Unlock() - if _, ok := m.idIndex[tableName]; !ok { - m.idIndex[tableName] = make(map[string]*list.Element) - } - tid := genID(tableName, id) - if v, err := m.store.Get(tid); err == nil { - if el, ok := m.idIndex[tableName][id]; ok { - lastTime := el.Value.(*idNode).lastVisit - // if expired, remove the node and return nil - if time.Now().Sub(lastTime) > m.Expired { - m.delBean(tableName, id) - return nil - } - m.idList.MoveToBack(el) - el.Value.(*idNode).lastVisit = time.Now() - } else { - el = m.idList.PushBack(newIDNode(tableName, id)) - m.idIndex[tableName][id] = el - } - return v - } - - // store bean is not exist, then remove memory's index - m.delBean(tableName, id) - return nil -} - -// clearIds clears all sql-ids mapping on table tableName from cache -func (m *LRUCacher) clearIds(tableName string) { - if tis, ok := m.sqlIndex[tableName]; ok { - for sql, v := range tis { - m.sqlList.Remove(v) - m.store.Del(sql) - } - } - m.sqlIndex[tableName] = make(map[string]*list.Element) -} - -// ClearIds clears all sql-ids mapping on table tableName from cache -func (m *LRUCacher) ClearIds(tableName string) { - m.mutex.Lock() - m.clearIds(tableName) - m.mutex.Unlock() -} - -func (m *LRUCacher) clearBeans(tableName string) { - if tis, ok := m.idIndex[tableName]; ok { - for id, v := range tis { - m.idList.Remove(v) - tid := genID(tableName, id) - m.store.Del(tid) - } - } - m.idIndex[tableName] = make(map[string]*list.Element) -} - -// ClearBeans clears all beans in some table -func (m *LRUCacher) ClearBeans(tableName string) { - m.mutex.Lock() - m.clearBeans(tableName) - m.mutex.Unlock() -} - -// PutIds pus ids into table -func (m *LRUCacher) PutIds(tableName, sql string, ids interface{}) { - m.mutex.Lock() - if _, ok := m.sqlIndex[tableName]; !ok { - m.sqlIndex[tableName] = make(map[string]*list.Element) - } - if el, ok := m.sqlIndex[tableName][sql]; !ok { - el = m.sqlList.PushBack(newSQLNode(tableName, sql)) - m.sqlIndex[tableName][sql] = el - } else { - el.Value.(*sqlNode).lastVisit = time.Now() - } - m.store.Put(sql, ids) - if m.sqlList.Len() > m.MaxElementSize { - e := m.sqlList.Front() - node := e.Value.(*sqlNode) - m.delIds(node.tbName, node.sql) - } - m.mutex.Unlock() -} - -// PutBean puts beans into table -func (m *LRUCacher) PutBean(tableName string, id string, obj interface{}) { - m.mutex.Lock() - var el *list.Element - var ok bool - - if el, ok = m.idIndex[tableName][id]; !ok { - el = m.idList.PushBack(newIDNode(tableName, id)) - m.idIndex[tableName][id] = el - } else { - el.Value.(*idNode).lastVisit = time.Now() - } - - m.store.Put(genID(tableName, id), obj) - if m.idList.Len() > m.MaxElementSize { - e := m.idList.Front() - node := e.Value.(*idNode) - m.delBean(node.tbName, node.id) - } - m.mutex.Unlock() -} - -func (m *LRUCacher) delIds(tableName, sql string) { - if _, ok := m.sqlIndex[tableName]; ok { - if el, ok := m.sqlIndex[tableName][sql]; ok { - delete(m.sqlIndex[tableName], sql) - m.sqlList.Remove(el) - } - } - m.store.Del(sql) -} - -// DelIds deletes ids -func (m *LRUCacher) DelIds(tableName, sql string) { - m.mutex.Lock() - m.delIds(tableName, sql) - m.mutex.Unlock() -} - -func (m *LRUCacher) delBean(tableName string, id string) { - tid := genID(tableName, id) - if el, ok := m.idIndex[tableName][id]; ok { - delete(m.idIndex[tableName], id) - m.idList.Remove(el) - m.clearIds(tableName) - } - m.store.Del(tid) -} - -// DelBean deletes beans in some table -func (m *LRUCacher) DelBean(tableName string, id string) { - m.mutex.Lock() - m.delBean(tableName, id) - m.mutex.Unlock() -} - -type idNode struct { - tbName string - id string - lastVisit time.Time -} - -type sqlNode struct { - tbName string - sql string - lastVisit time.Time -} - -func genSQLKey(sql string, args interface{}) string { - return fmt.Sprintf("%v-%v", sql, args) -} - -func genID(prefix string, id string) string { - return fmt.Sprintf("%v-%v", prefix, id) -} - -func newIDNode(tbName string, id string) *idNode { - return &idNode{tbName, id, time.Now()} -} - -func newSQLNode(tbName, sql string) *sqlNode { - return &sqlNode{tbName, sql, time.Now()} -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/cache_lru_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/cache_lru_test.go deleted file mode 100644 index 7da36f007..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/cache_lru_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "testing" - - "xorm.io/core" - "github.com/stretchr/testify/assert" -) - -func TestLRUCache(t *testing.T) { - type CacheObject1 struct { - Id int64 - } - - store := NewMemoryStore() - cacher := NewLRUCacher(store, 10000) - - tableName := "cache_object1" - pks := []core.PK{ - {1}, - {2}, - } - - for _, pk := range pks { - sid, err := pk.ToString() - assert.NoError(t, err) - - cacher.PutIds(tableName, "select * from cache_object1", sid) - ids := cacher.GetIds(tableName, "select * from cache_object1") - assert.EqualValues(t, sid, ids) - - cacher.ClearIds(tableName) - ids2 := cacher.GetIds(tableName, "select * from cache_object1") - assert.Nil(t, ids2) - - obj2 := cacher.GetBean(tableName, sid) - assert.Nil(t, obj2) - - var obj = new(CacheObject1) - cacher.PutBean(tableName, sid, obj) - obj3 := cacher.GetBean(tableName, sid) - assert.EqualValues(t, obj, obj3) - - cacher.DelBean(tableName, sid) - obj4 := cacher.GetBean(tableName, sid) - assert.Nil(t, obj4) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/cache_memory_store.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/cache_memory_store.go deleted file mode 100644 index 0c483f458..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/cache_memory_store.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "sync" - - "xorm.io/core" -) - -var _ core.CacheStore = NewMemoryStore() - -// MemoryStore represents in-memory store -type MemoryStore struct { - store map[interface{}]interface{} - mutex sync.RWMutex -} - -// NewMemoryStore creates a new store in memory -func NewMemoryStore() *MemoryStore { - return &MemoryStore{store: make(map[interface{}]interface{})} -} - -// Put puts object into store -func (s *MemoryStore) Put(key string, value interface{}) error { - s.mutex.Lock() - defer s.mutex.Unlock() - s.store[key] = value - return nil -} - -// Get gets object from store -func (s *MemoryStore) Get(key string) (interface{}, error) { - s.mutex.RLock() - defer s.mutex.RUnlock() - if v, ok := s.store[key]; ok { - return v, nil - } - - return nil, ErrNotExist -} - -// Del deletes object -func (s *MemoryStore) Del(key string) error { - s.mutex.Lock() - defer s.mutex.Unlock() - delete(s.store, key) - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/context_cache.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/context_cache.go deleted file mode 100644 index 1bc228849..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/context_cache.go +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright 2018 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -// ContextCache is the interface that operates the cache data. -type ContextCache interface { - // Put puts value into cache with key. - Put(key string, val interface{}) - // Get gets cached value by given key. - Get(key string) interface{} -} - -type memoryContextCache map[string]interface{} - -// NewMemoryContextCache return memoryContextCache -func NewMemoryContextCache() memoryContextCache { - return make(map[string]interface{}) -} - -// Put puts value into cache with key. -func (m memoryContextCache) Put(key string, val interface{}) { - m[key] = val -} - -// Get gets cached value by given key. -func (m memoryContextCache) Get(key string) interface{} { - return m[key] -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/convert.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/convert.go deleted file mode 100644 index 2316ca0b4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/convert.go +++ /dev/null @@ -1,348 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql/driver" - "errors" - "fmt" - "reflect" - "strconv" - "time" -) - -var errNilPtr = errors.New("destination pointer is nil") // embedded in descriptive error - -func strconvErr(err error) error { - if ne, ok := err.(*strconv.NumError); ok { - return ne.Err - } - return err -} - -func cloneBytes(b []byte) []byte { - if b == nil { - return nil - } else { - c := make([]byte, len(b)) - copy(c, b) - return c - } -} - -func asString(src interface{}) string { - switch v := src.(type) { - case string: - return v - case []byte: - return string(v) - } - rv := reflect.ValueOf(src) - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return strconv.FormatInt(rv.Int(), 10) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return strconv.FormatUint(rv.Uint(), 10) - case reflect.Float64: - return strconv.FormatFloat(rv.Float(), 'g', -1, 64) - case reflect.Float32: - return strconv.FormatFloat(rv.Float(), 'g', -1, 32) - case reflect.Bool: - return strconv.FormatBool(rv.Bool()) - } - return fmt.Sprintf("%v", src) -} - -func asBytes(buf []byte, rv reflect.Value) (b []byte, ok bool) { - switch rv.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return strconv.AppendInt(buf, rv.Int(), 10), true - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return strconv.AppendUint(buf, rv.Uint(), 10), true - case reflect.Float32: - return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 32), true - case reflect.Float64: - return strconv.AppendFloat(buf, rv.Float(), 'g', -1, 64), true - case reflect.Bool: - return strconv.AppendBool(buf, rv.Bool()), true - case reflect.String: - s := rv.String() - return append(buf, s...), true - } - return -} - -// convertAssign copies to dest the value in src, converting it if possible. -// An error is returned if the copy would result in loss of information. -// dest should be a pointer type. -func convertAssign(dest, src interface{}) error { - // Common cases, without reflect. - switch s := src.(type) { - case string: - switch d := dest.(type) { - case *string: - if d == nil { - return errNilPtr - } - *d = s - return nil - case *[]byte: - if d == nil { - return errNilPtr - } - *d = []byte(s) - return nil - } - case []byte: - switch d := dest.(type) { - case *string: - if d == nil { - return errNilPtr - } - *d = string(s) - return nil - case *interface{}: - if d == nil { - return errNilPtr - } - *d = cloneBytes(s) - return nil - case *[]byte: - if d == nil { - return errNilPtr - } - *d = cloneBytes(s) - return nil - } - - case time.Time: - switch d := dest.(type) { - case *string: - *d = s.Format(time.RFC3339Nano) - return nil - case *[]byte: - if d == nil { - return errNilPtr - } - *d = []byte(s.Format(time.RFC3339Nano)) - return nil - } - case nil: - switch d := dest.(type) { - case *interface{}: - if d == nil { - return errNilPtr - } - *d = nil - return nil - case *[]byte: - if d == nil { - return errNilPtr - } - *d = nil - return nil - } - } - - var sv reflect.Value - - switch d := dest.(type) { - case *string: - sv = reflect.ValueOf(src) - switch sv.Kind() { - case reflect.Bool, - reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, - reflect.Float32, reflect.Float64: - *d = asString(src) - return nil - } - case *[]byte: - sv = reflect.ValueOf(src) - if b, ok := asBytes(nil, sv); ok { - *d = b - return nil - } - case *bool: - bv, err := driver.Bool.ConvertValue(src) - if err == nil { - *d = bv.(bool) - } - return err - case *interface{}: - *d = src - return nil - } - - dpv := reflect.ValueOf(dest) - if dpv.Kind() != reflect.Ptr { - return errors.New("destination not a pointer") - } - if dpv.IsNil() { - return errNilPtr - } - - if !sv.IsValid() { - sv = reflect.ValueOf(src) - } - - dv := reflect.Indirect(dpv) - if sv.IsValid() && sv.Type().AssignableTo(dv.Type()) { - switch b := src.(type) { - case []byte: - dv.Set(reflect.ValueOf(cloneBytes(b))) - default: - dv.Set(sv) - } - return nil - } - - if dv.Kind() == sv.Kind() && sv.Type().ConvertibleTo(dv.Type()) { - dv.Set(sv.Convert(dv.Type())) - return nil - } - - switch dv.Kind() { - case reflect.Ptr: - if src == nil { - dv.Set(reflect.Zero(dv.Type())) - return nil - } - - dv.Set(reflect.New(dv.Type().Elem())) - return convertAssign(dv.Interface(), src) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - s := asString(src) - i64, err := strconv.ParseInt(s, 10, dv.Type().Bits()) - if err != nil { - err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) - } - dv.SetInt(i64) - return nil - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - s := asString(src) - u64, err := strconv.ParseUint(s, 10, dv.Type().Bits()) - if err != nil { - err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) - } - dv.SetUint(u64) - return nil - case reflect.Float32, reflect.Float64: - s := asString(src) - f64, err := strconv.ParseFloat(s, dv.Type().Bits()) - if err != nil { - err = strconvErr(err) - return fmt.Errorf("converting driver.Value type %T (%q) to a %s: %v", src, s, dv.Kind(), err) - } - dv.SetFloat(f64) - return nil - case reflect.String: - dv.SetString(asString(src)) - return nil - } - - return fmt.Errorf("unsupported Scan, storing driver.Value type %T into type %T", src, dest) -} - -func asKind(vv reflect.Value, tp reflect.Type) (interface{}, error) { - switch tp.Kind() { - case reflect.Int64: - return vv.Int(), nil - case reflect.Int: - return int(vv.Int()), nil - case reflect.Int32: - return int32(vv.Int()), nil - case reflect.Int16: - return int16(vv.Int()), nil - case reflect.Int8: - return int8(vv.Int()), nil - case reflect.Uint64: - return vv.Uint(), nil - case reflect.Uint: - return uint(vv.Uint()), nil - case reflect.Uint32: - return uint32(vv.Uint()), nil - case reflect.Uint16: - return uint16(vv.Uint()), nil - case reflect.Uint8: - return uint8(vv.Uint()), nil - case reflect.String: - return vv.String(), nil - case reflect.Slice: - if tp.Elem().Kind() == reflect.Uint8 { - v, err := strconv.ParseInt(string(vv.Interface().([]byte)), 10, 64) - if err != nil { - return nil, err - } - return v, nil - } - - } - return nil, fmt.Errorf("unsupported primary key type: %v, %v", tp, vv) -} - -func convertFloat(v interface{}) (float64, error) { - switch v.(type) { - case float32: - return float64(v.(float32)), nil - case float64: - return v.(float64), nil - case string: - i, err := strconv.ParseFloat(v.(string), 64) - if err != nil { - return 0, err - } - return i, nil - case []byte: - i, err := strconv.ParseFloat(string(v.([]byte)), 64) - if err != nil { - return 0, err - } - return i, nil - } - return 0, fmt.Errorf("unsupported type: %v", v) -} - -func convertInt(v interface{}) (int64, error) { - switch v.(type) { - case int: - return int64(v.(int)), nil - case int8: - return int64(v.(int8)), nil - case int16: - return int64(v.(int16)), nil - case int32: - return int64(v.(int32)), nil - case int64: - return v.(int64), nil - case []byte: - i, err := strconv.ParseInt(string(v.([]byte)), 10, 64) - if err != nil { - return 0, err - } - return i, nil - case string: - i, err := strconv.ParseInt(v.(string), 10, 64) - if err != nil { - return 0, err - } - return i, nil - } - return 0, fmt.Errorf("unsupported type: %v", v) -} - -func asBool(bs []byte) (bool, error) { - if len(bs) == 0 { - return false, nil - } - if bs[0] == 0x00 { - return false, nil - } else if bs[0] == 0x01 { - return true, nil - } - return strconv.ParseBool(string(bs)) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_mssql.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_mssql.go deleted file mode 100644 index 29070da2f..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_mssql.go +++ /dev/null @@ -1,567 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "net/url" - "strconv" - "strings" - - "xorm.io/core" -) - -var ( - mssqlReservedWords = map[string]bool{ - "ADD": true, - "EXTERNAL": true, - "PROCEDURE": true, - "ALL": true, - "FETCH": true, - "PUBLIC": true, - "ALTER": true, - "FILE": true, - "RAISERROR": true, - "AND": true, - "FILLFACTOR": true, - "READ": true, - "ANY": true, - "FOR": true, - "READTEXT": true, - "AS": true, - "FOREIGN": true, - "RECONFIGURE": true, - "ASC": true, - "FREETEXT": true, - "REFERENCES": true, - "AUTHORIZATION": true, - "FREETEXTTABLE": true, - "REPLICATION": true, - "BACKUP": true, - "FROM": true, - "RESTORE": true, - "BEGIN": true, - "FULL": true, - "RESTRICT": true, - "BETWEEN": true, - "FUNCTION": true, - "RETURN": true, - "BREAK": true, - "GOTO": true, - "REVERT": true, - "BROWSE": true, - "GRANT": true, - "REVOKE": true, - "BULK": true, - "GROUP": true, - "RIGHT": true, - "BY": true, - "HAVING": true, - "ROLLBACK": true, - "CASCADE": true, - "HOLDLOCK": true, - "ROWCOUNT": true, - "CASE": true, - "IDENTITY": true, - "ROWGUIDCOL": true, - "CHECK": true, - "IDENTITY_INSERT": true, - "RULE": true, - "CHECKPOINT": true, - "IDENTITYCOL": true, - "SAVE": true, - "CLOSE": true, - "IF": true, - "SCHEMA": true, - "CLUSTERED": true, - "IN": true, - "SECURITYAUDIT": true, - "COALESCE": true, - "INDEX": true, - "SELECT": true, - "COLLATE": true, - "INNER": true, - "SEMANTICKEYPHRASETABLE": true, - "COLUMN": true, - "INSERT": true, - "SEMANTICSIMILARITYDETAILSTABLE": true, - "COMMIT": true, - "INTERSECT": true, - "SEMANTICSIMILARITYTABLE": true, - "COMPUTE": true, - "INTO": true, - "SESSION_USER": true, - "CONSTRAINT": true, - "IS": true, - "SET": true, - "CONTAINS": true, - "JOIN": true, - "SETUSER": true, - "CONTAINSTABLE": true, - "KEY": true, - "SHUTDOWN": true, - "CONTINUE": true, - "KILL": true, - "SOME": true, - "CONVERT": true, - "LEFT": true, - "STATISTICS": true, - "CREATE": true, - "LIKE": true, - "SYSTEM_USER": true, - "CROSS": true, - "LINENO": true, - "TABLE": true, - "CURRENT": true, - "LOAD": true, - "TABLESAMPLE": true, - "CURRENT_DATE": true, - "MERGE": true, - "TEXTSIZE": true, - "CURRENT_TIME": true, - "NATIONAL": true, - "THEN": true, - "CURRENT_TIMESTAMP": true, - "NOCHECK": true, - "TO": true, - "CURRENT_USER": true, - "NONCLUSTERED": true, - "TOP": true, - "CURSOR": true, - "NOT": true, - "TRAN": true, - "DATABASE": true, - "NULL": true, - "TRANSACTION": true, - "DBCC": true, - "NULLIF": true, - "TRIGGER": true, - "DEALLOCATE": true, - "OF": true, - "TRUNCATE": true, - "DECLARE": true, - "OFF": true, - "TRY_CONVERT": true, - "DEFAULT": true, - "OFFSETS": true, - "TSEQUAL": true, - "DELETE": true, - "ON": true, - "UNION": true, - "DENY": true, - "OPEN": true, - "UNIQUE": true, - "DESC": true, - "OPENDATASOURCE": true, - "UNPIVOT": true, - "DISK": true, - "OPENQUERY": true, - "UPDATE": true, - "DISTINCT": true, - "OPENROWSET": true, - "UPDATETEXT": true, - "DISTRIBUTED": true, - "OPENXML": true, - "USE": true, - "DOUBLE": true, - "OPTION": true, - "USER": true, - "DROP": true, - "OR": true, - "VALUES": true, - "DUMP": true, - "ORDER": true, - "VARYING": true, - "ELSE": true, - "OUTER": true, - "VIEW": true, - "END": true, - "OVER": true, - "WAITFOR": true, - "ERRLVL": true, - "PERCENT": true, - "WHEN": true, - "ESCAPE": true, - "PIVOT": true, - "WHERE": true, - "EXCEPT": true, - "PLAN": true, - "WHILE": true, - "EXEC": true, - "PRECISION": true, - "WITH": true, - "EXECUTE": true, - "PRIMARY": true, - "WITHIN": true, - "EXISTS": true, - "PRINT": true, - "WRITETEXT": true, - "EXIT": true, - "PROC": true, - } -) - -type mssql struct { - core.Base -} - -func (db *mssql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { - return db.Base.Init(d, db, uri, drivername, dataSourceName) -} - -func (db *mssql) SqlType(c *core.Column) string { - var res string - switch t := c.SQLType.Name; t { - case core.Bool: - res = core.Bit - if strings.EqualFold(c.Default, "true") { - c.Default = "1" - } else if strings.EqualFold(c.Default, "false") { - c.Default = "0" - } - case core.Serial: - c.IsAutoIncrement = true - c.IsPrimaryKey = true - c.Nullable = false - res = core.Int - case core.BigSerial: - c.IsAutoIncrement = true - c.IsPrimaryKey = true - c.Nullable = false - res = core.BigInt - case core.Bytea, core.Blob, core.Binary, core.TinyBlob, core.MediumBlob, core.LongBlob: - res = core.VarBinary - if c.Length == 0 { - c.Length = 50 - } - case core.TimeStamp: - res = core.DateTime - case core.TimeStampz: - res = "DATETIMEOFFSET" - c.Length = 7 - case core.MediumInt: - res = core.Int - case core.Text, core.MediumText, core.TinyText, core.LongText, core.Json: - res = core.Varchar + "(MAX)" - case core.Double: - res = core.Real - case core.Uuid: - res = core.Varchar - c.Length = 40 - case core.TinyInt: - res = core.TinyInt - c.Length = 0 - case core.BigInt: - res = core.BigInt - c.Length = 0 - default: - res = t - } - - if res == core.Int { - return core.Int - } - - hasLen1 := (c.Length > 0) - hasLen2 := (c.Length2 > 0) - - if hasLen2 { - res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")" - } else if hasLen1 { - res += "(" + strconv.Itoa(c.Length) + ")" - } - return res -} - -func (db *mssql) SupportInsertMany() bool { - return true -} - -func (db *mssql) IsReserved(name string) bool { - _, ok := mssqlReservedWords[name] - return ok -} - -func (db *mssql) Quote(name string) string { - return "\"" + name + "\"" -} - -func (db *mssql) SupportEngine() bool { - return false -} - -func (db *mssql) AutoIncrStr() string { - return "IDENTITY" -} - -func (db *mssql) DropTableSql(tableName string) string { - return fmt.Sprintf("IF EXISTS (SELECT * FROM sysobjects WHERE id = "+ - "object_id(N'%s') and OBJECTPROPERTY(id, N'IsUserTable') = 1) "+ - "DROP TABLE \"%s\"", tableName, tableName) -} - -func (db *mssql) SupportCharset() bool { - return false -} - -func (db *mssql) IndexOnTable() bool { - return true -} - -func (db *mssql) IndexCheckSql(tableName, idxName string) (string, []interface{}) { - args := []interface{}{idxName} - sql := "select name from sysindexes where id=object_id('" + tableName + "') and name=?" - return sql, args -} - -/*func (db *mssql) ColumnCheckSql(tableName, colName string) (string, []interface{}) { - args := []interface{}{tableName, colName} - sql := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?` - return sql, args -}*/ - -func (db *mssql) IsColumnExist(tableName, colName string) (bool, error) { - query := `SELECT "COLUMN_NAME" FROM "INFORMATION_SCHEMA"."COLUMNS" WHERE "TABLE_NAME" = ? AND "COLUMN_NAME" = ?` - - return db.HasRecords(query, tableName, colName) -} - -func (db *mssql) TableCheckSql(tableName string) (string, []interface{}) { - args := []interface{}{} - sql := "select * from sysobjects where id = object_id(N'" + tableName + "') and OBJECTPROPERTY(id, N'IsUserTable') = 1" - return sql, args -} - -func (db *mssql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { - args := []interface{}{} - s := `select a.name as name, b.name as ctype,a.max_length,a.precision,a.scale,a.is_nullable as nullable, - "default_is_null" = (CASE WHEN c.text is null THEN 1 ELSE 0 END), - replace(replace(isnull(c.text,''),'(',''),')','') as vdefault, - ISNULL(i.is_primary_key, 0), a.is_identity as is_identity - from sys.columns a - left join sys.types b on a.user_type_id=b.user_type_id - left join sys.syscomments c on a.default_object_id=c.id - LEFT OUTER JOIN - sys.index_columns ic ON ic.object_id = a.object_id AND ic.column_id = a.column_id - LEFT OUTER JOIN - sys.indexes i ON ic.object_id = i.object_id AND ic.index_id = i.index_id - where a.object_id=object_id('` + tableName + `')` - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, nil, err - } - defer rows.Close() - - cols := make(map[string]*core.Column) - colSeq := make([]string, 0) - for rows.Next() { - var name, ctype, vdefault string - var maxLen, precision, scale int - var nullable, isPK, defaultIsNull, isIncrement bool - err = rows.Scan(&name, &ctype, &maxLen, &precision, &scale, &nullable, &defaultIsNull, &vdefault, &isPK, &isIncrement) - if err != nil { - return nil, nil, err - } - - col := new(core.Column) - col.Indexes = make(map[string]int) - col.Name = strings.Trim(name, "` ") - col.Nullable = nullable - col.DefaultIsEmpty = defaultIsNull - if !defaultIsNull { - col.Default = vdefault - } - col.IsPrimaryKey = isPK - col.IsAutoIncrement = isIncrement - ct := strings.ToUpper(ctype) - if ct == "DECIMAL" { - col.Length = precision - col.Length2 = scale - } else { - col.Length = maxLen - } - switch ct { - case "DATETIMEOFFSET": - col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0} - case "NVARCHAR": - col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: 0, DefaultLength2: 0} - case "IMAGE": - col.SQLType = core.SQLType{Name: core.VarBinary, DefaultLength: 0, DefaultLength2: 0} - default: - if _, ok := core.SqlTypes[ct]; ok { - col.SQLType = core.SQLType{Name: ct, DefaultLength: 0, DefaultLength2: 0} - } else { - return nil, nil, fmt.Errorf("Unknown colType %v for %v - %v", ct, tableName, col.Name) - } - } - - cols[col.Name] = col - colSeq = append(colSeq, col.Name) - } - return colSeq, cols, nil -} - -func (db *mssql) GetTables() ([]*core.Table, error) { - args := []interface{}{} - s := `select name from sysobjects where xtype ='U'` - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - tables := make([]*core.Table, 0) - for rows.Next() { - table := core.NewEmptyTable() - var name string - err = rows.Scan(&name) - if err != nil { - return nil, err - } - table.Name = strings.Trim(name, "` ") - tables = append(tables, table) - } - return tables, nil -} - -func (db *mssql) GetIndexes(tableName string) (map[string]*core.Index, error) { - args := []interface{}{tableName} - s := `SELECT -IXS.NAME AS [INDEX_NAME], -C.NAME AS [COLUMN_NAME], -IXS.is_unique AS [IS_UNIQUE] -FROM SYS.INDEXES IXS -INNER JOIN SYS.INDEX_COLUMNS IXCS -ON IXS.OBJECT_ID=IXCS.OBJECT_ID AND IXS.INDEX_ID = IXCS.INDEX_ID -INNER JOIN SYS.COLUMNS C ON IXS.OBJECT_ID=C.OBJECT_ID -AND IXCS.COLUMN_ID=C.COLUMN_ID -WHERE IXS.TYPE_DESC='NONCLUSTERED' and OBJECT_NAME(IXS.OBJECT_ID) =? -` - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - indexes := make(map[string]*core.Index, 0) - for rows.Next() { - var indexType int - var indexName, colName, isUnique string - - err = rows.Scan(&indexName, &colName, &isUnique) - if err != nil { - return nil, err - } - - i, err := strconv.ParseBool(isUnique) - if err != nil { - return nil, err - } - - if i { - indexType = core.UniqueType - } else { - indexType = core.IndexType - } - - colName = strings.Trim(colName, "` ") - var isRegular bool - if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { - indexName = indexName[5+len(tableName):] - isRegular = true - } - - var index *core.Index - var ok bool - if index, ok = indexes[indexName]; !ok { - index = new(core.Index) - index.Type = indexType - index.Name = indexName - index.IsRegular = isRegular - indexes[indexName] = index - } - index.AddColumn(colName) - } - return indexes, nil -} - -func (db *mssql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string { - var sql string - if tableName == "" { - tableName = table.Name - } - - sql = "IF NOT EXISTS (SELECT [name] FROM sys.tables WHERE [name] = '" + tableName + "' ) CREATE TABLE " - - sql += db.Quote(tableName) + " (" - - pkList := table.PrimaryKeys - - for _, colName := range table.ColumnsSeq() { - col := table.GetColumn(colName) - if col.IsPrimaryKey && len(pkList) == 1 { - sql += col.String(db) - } else { - sql += col.StringNoPk(db) - } - sql = strings.TrimSpace(sql) - sql += ", " - } - - if len(pkList) > 1 { - sql += "PRIMARY KEY ( " - sql += strings.Join(pkList, ",") - sql += " ), " - } - - sql = sql[:len(sql)-2] + ")" - sql += ";" - return sql -} - -func (db *mssql) ForUpdateSql(query string) string { - return query -} - -func (db *mssql) Filters() []core.Filter { - return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}} -} - -type odbcDriver struct { -} - -func (p *odbcDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - var dbName string - - if strings.HasPrefix(dataSourceName, "sqlserver://") { - u, err := url.Parse(dataSourceName) - if err != nil { - return nil, err - } - dbName = u.Query().Get("database") - } else { - kv := strings.Split(dataSourceName, ";") - for _, c := range kv { - vv := strings.Split(strings.TrimSpace(c), "=") - if len(vv) == 2 { - switch strings.ToLower(vv[0]) { - case "database": - dbName = vv[1] - } - } - } - } - if dbName == "" { - return nil, errors.New("no db name provided") - } - return &core.Uri{DbName: dbName, DbType: core.MSSQL}, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_mysql.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_mysql.go deleted file mode 100644 index cf1dbb6f2..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_mysql.go +++ /dev/null @@ -1,654 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "crypto/tls" - "errors" - "fmt" - "regexp" - "strconv" - "strings" - "time" - - "xorm.io/core" -) - -var ( - mysqlReservedWords = map[string]bool{ - "ADD": true, - "ALL": true, - "ALTER": true, - "ANALYZE": true, - "AND": true, - "AS": true, - "ASC": true, - "ASENSITIVE": true, - "BEFORE": true, - "BETWEEN": true, - "BIGINT": true, - "BINARY": true, - "BLOB": true, - "BOTH": true, - "BY": true, - "CALL": true, - "CASCADE": true, - "CASE": true, - "CHANGE": true, - "CHAR": true, - "CHARACTER": true, - "CHECK": true, - "COLLATE": true, - "COLUMN": true, - "CONDITION": true, - "CONNECTION": true, - "CONSTRAINT": true, - "CONTINUE": true, - "CONVERT": true, - "CREATE": true, - "CROSS": true, - "CURRENT_DATE": true, - "CURRENT_TIME": true, - "CURRENT_TIMESTAMP": true, - "CURRENT_USER": true, - "CURSOR": true, - "DATABASE": true, - "DATABASES": true, - "DAY_HOUR": true, - "DAY_MICROSECOND": true, - "DAY_MINUTE": true, - "DAY_SECOND": true, - "DEC": true, - "DECIMAL": true, - "DECLARE": true, - "DEFAULT": true, - "DELAYED": true, - "DELETE": true, - "DESC": true, - "DESCRIBE": true, - "DETERMINISTIC": true, - "DISTINCT": true, - "DISTINCTROW": true, - "DIV": true, - "DOUBLE": true, - "DROP": true, - "DUAL": true, - "EACH": true, - "ELSE": true, - "ELSEIF": true, - "ENCLOSED": true, - "ESCAPED": true, - "EXISTS": true, - "EXIT": true, - "EXPLAIN": true, - "FALSE": true, - "FETCH": true, - "FLOAT": true, - "FLOAT4": true, - "FLOAT8": true, - "FOR": true, - "FORCE": true, - "FOREIGN": true, - "FROM": true, - "FULLTEXT": true, - "GOTO": true, - "GRANT": true, - "GROUP": true, - "HAVING": true, - "HIGH_PRIORITY": true, - "HOUR_MICROSECOND": true, - "HOUR_MINUTE": true, - "HOUR_SECOND": true, - "IF": true, - "IGNORE": true, - "IN": true, "INDEX": true, - "INFILE": true, "INNER": true, "INOUT": true, - "INSENSITIVE": true, "INSERT": true, "INT": true, - "INT1": true, "INT2": true, "INT3": true, - "INT4": true, "INT8": true, "INTEGER": true, - "INTERVAL": true, "INTO": true, "IS": true, - "ITERATE": true, "JOIN": true, "KEY": true, - "KEYS": true, "KILL": true, "LABEL": true, - "LEADING": true, "LEAVE": true, "LEFT": true, - "LIKE": true, "LIMIT": true, "LINEAR": true, - "LINES": true, "LOAD": true, "LOCALTIME": true, - "LOCALTIMESTAMP": true, "LOCK": true, "LONG": true, - "LONGBLOB": true, "LONGTEXT": true, "LOOP": true, - "LOW_PRIORITY": true, "MATCH": true, "MEDIUMBLOB": true, - "MEDIUMINT": true, "MEDIUMTEXT": true, "MIDDLEINT": true, - "MINUTE_MICROSECOND": true, "MINUTE_SECOND": true, "MOD": true, - "MODIFIES": true, "NATURAL": true, "NOT": true, - "NO_WRITE_TO_BINLOG": true, "NULL": true, "NUMERIC": true, - "ON OPTIMIZE": true, "OPTION": true, - "OPTIONALLY": true, "OR": true, "ORDER": true, - "OUT": true, "OUTER": true, "OUTFILE": true, - "PRECISION": true, "PRIMARY": true, "PROCEDURE": true, - "PURGE": true, "RAID0": true, "RANGE": true, - "READ": true, "READS": true, "REAL": true, - "REFERENCES": true, "REGEXP": true, "RELEASE": true, - "RENAME": true, "REPEAT": true, "REPLACE": true, - "REQUIRE": true, "RESTRICT": true, "RETURN": true, - "REVOKE": true, "RIGHT": true, "RLIKE": true, - "SCHEMA": true, "SCHEMAS": true, "SECOND_MICROSECOND": true, - "SELECT": true, "SENSITIVE": true, "SEPARATOR": true, - "SET": true, "SHOW": true, "SMALLINT": true, - "SPATIAL": true, "SPECIFIC": true, "SQL": true, - "SQLEXCEPTION": true, "SQLSTATE": true, "SQLWARNING": true, - "SQL_BIG_RESULT": true, "SQL_CALC_FOUND_ROWS": true, "SQL_SMALL_RESULT": true, - "SSL": true, "STARTING": true, "STRAIGHT_JOIN": true, - "TABLE": true, "TERMINATED": true, "THEN": true, - "TINYBLOB": true, "TINYINT": true, "TINYTEXT": true, - "TO": true, "TRAILING": true, "TRIGGER": true, - "TRUE": true, "UNDO": true, "UNION": true, - "UNIQUE": true, "UNLOCK": true, "UNSIGNED": true, - "UPDATE": true, "USAGE": true, "USE": true, - "USING": true, "UTC_DATE": true, "UTC_TIME": true, - "UTC_TIMESTAMP": true, "VALUES": true, "VARBINARY": true, - "VARCHAR": true, - "VARCHARACTER": true, - "VARYING": true, - "WHEN": true, - "WHERE": true, - "WHILE": true, - "WITH": true, - "WRITE": true, - "X509": true, - "XOR": true, - "YEAR_MONTH": true, - "ZEROFILL": true, - } -) - -type mysql struct { - core.Base - net string - addr string - params map[string]string - loc *time.Location - timeout time.Duration - tls *tls.Config - allowAllFiles bool - allowOldPasswords bool - clientFoundRows bool - rowFormat string -} - -func (db *mysql) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { - return db.Base.Init(d, db, uri, drivername, dataSourceName) -} - -func (db *mysql) SetParams(params map[string]string) { - rowFormat, ok := params["rowFormat"] - if ok { - var t = strings.ToUpper(rowFormat) - switch t { - case "COMPACT": - fallthrough - case "REDUNDANT": - fallthrough - case "DYNAMIC": - fallthrough - case "COMPRESSED": - db.rowFormat = t - break - default: - break - } - } -} - -func (db *mysql) SqlType(c *core.Column) string { - var res string - switch t := c.SQLType.Name; t { - case core.Bool: - res = core.TinyInt - c.Length = 1 - case core.Serial: - c.IsAutoIncrement = true - c.IsPrimaryKey = true - c.Nullable = false - res = core.Int - case core.BigSerial: - c.IsAutoIncrement = true - c.IsPrimaryKey = true - c.Nullable = false - res = core.BigInt - case core.Bytea: - res = core.Blob - case core.TimeStampz: - res = core.Char - c.Length = 64 - case core.Enum: // mysql enum - res = core.Enum - res += "(" - opts := "" - for v := range c.EnumOptions { - opts += fmt.Sprintf(",'%v'", v) - } - res += strings.TrimLeft(opts, ",") - res += ")" - case core.Set: // mysql set - res = core.Set - res += "(" - opts := "" - for v := range c.SetOptions { - opts += fmt.Sprintf(",'%v'", v) - } - res += strings.TrimLeft(opts, ",") - res += ")" - case core.NVarchar: - res = core.Varchar - case core.Uuid: - res = core.Varchar - c.Length = 40 - case core.Json: - res = core.Text - default: - res = t - } - - hasLen1 := (c.Length > 0) - hasLen2 := (c.Length2 > 0) - - if res == core.BigInt && !hasLen1 && !hasLen2 { - c.Length = 20 - hasLen1 = true - } - - if hasLen2 { - res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")" - } else if hasLen1 { - res += "(" + strconv.Itoa(c.Length) + ")" - } - return res -} - -func (db *mysql) SupportInsertMany() bool { - return true -} - -func (db *mysql) IsReserved(name string) bool { - _, ok := mysqlReservedWords[name] - return ok -} - -func (db *mysql) Quote(name string) string { - return "`" + name + "`" -} - -func (db *mysql) SupportEngine() bool { - return true -} - -func (db *mysql) AutoIncrStr() string { - return "AUTO_INCREMENT" -} - -func (db *mysql) SupportCharset() bool { - return true -} - -func (db *mysql) IndexOnTable() bool { - return true -} - -func (db *mysql) IndexCheckSql(tableName, idxName string) (string, []interface{}) { - args := []interface{}{db.DbName, tableName, idxName} - sql := "SELECT `INDEX_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS`" - sql += " WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `INDEX_NAME`=?" - return sql, args -} - -/*func (db *mysql) ColumnCheckSql(tableName, colName string) (string, []interface{}) { - args := []interface{}{db.DbName, tableName, colName} - sql := "SELECT `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ? AND `COLUMN_NAME` = ?" - return sql, args -}*/ - -func (db *mysql) TableCheckSql(tableName string) (string, []interface{}) { - args := []interface{}{db.DbName, tableName} - sql := "SELECT `TABLE_NAME` from `INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? and `TABLE_NAME`=?" - return sql, args -} - -func (db *mysql) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { - args := []interface{}{db.DbName, tableName} - s := "SELECT `COLUMN_NAME`, `IS_NULLABLE`, `COLUMN_DEFAULT`, `COLUMN_TYPE`," + - " `COLUMN_KEY`, `EXTRA`,`COLUMN_COMMENT` FROM `INFORMATION_SCHEMA`.`COLUMNS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, nil, err - } - defer rows.Close() - - cols := make(map[string]*core.Column) - colSeq := make([]string, 0) - for rows.Next() { - col := new(core.Column) - col.Indexes = make(map[string]int) - - var columnName, isNullable, colType, colKey, extra, comment string - var colDefault *string - err = rows.Scan(&columnName, &isNullable, &colDefault, &colType, &colKey, &extra, &comment) - if err != nil { - return nil, nil, err - } - col.Name = strings.Trim(columnName, "` ") - col.Comment = comment - if "YES" == isNullable { - col.Nullable = true - } - - if colDefault != nil { - col.Default = *colDefault - col.DefaultIsEmpty = false - } else { - col.DefaultIsEmpty = true - } - - cts := strings.Split(colType, "(") - colName := cts[0] - colType = strings.ToUpper(colName) - var len1, len2 int - if len(cts) == 2 { - idx := strings.Index(cts[1], ")") - if colType == core.Enum && cts[1][0] == '\'' { // enum - options := strings.Split(cts[1][0:idx], ",") - col.EnumOptions = make(map[string]int) - for k, v := range options { - v = strings.TrimSpace(v) - v = strings.Trim(v, "'") - col.EnumOptions[v] = k - } - } else if colType == core.Set && cts[1][0] == '\'' { - options := strings.Split(cts[1][0:idx], ",") - col.SetOptions = make(map[string]int) - for k, v := range options { - v = strings.TrimSpace(v) - v = strings.Trim(v, "'") - col.SetOptions[v] = k - } - } else { - lens := strings.Split(cts[1][0:idx], ",") - len1, err = strconv.Atoi(strings.TrimSpace(lens[0])) - if err != nil { - return nil, nil, err - } - if len(lens) == 2 { - len2, err = strconv.Atoi(lens[1]) - if err != nil { - return nil, nil, err - } - } - } - } - if colType == "FLOAT UNSIGNED" { - colType = "FLOAT" - } - if colType == "DOUBLE UNSIGNED" { - colType = "DOUBLE" - } - col.Length = len1 - col.Length2 = len2 - if _, ok := core.SqlTypes[colType]; ok { - col.SQLType = core.SQLType{Name: colType, DefaultLength: len1, DefaultLength2: len2} - } else { - return nil, nil, fmt.Errorf("Unknown colType %v", colType) - } - - if colKey == "PRI" { - col.IsPrimaryKey = true - } - if colKey == "UNI" { - // col.is - } - - if extra == "auto_increment" { - col.IsAutoIncrement = true - } - - if !col.DefaultIsEmpty { - if col.SQLType.IsText() { - col.Default = "'" + col.Default + "'" - } else if col.SQLType.IsTime() && col.Default != "CURRENT_TIMESTAMP" { - col.Default = "'" + col.Default + "'" - } - } - cols[col.Name] = col - colSeq = append(colSeq, col.Name) - } - return colSeq, cols, nil -} - -func (db *mysql) GetTables() ([]*core.Table, error) { - args := []interface{}{db.DbName} - s := "SELECT `TABLE_NAME`, `ENGINE`, `TABLE_ROWS`, `AUTO_INCREMENT`, `TABLE_COMMENT` from " + - "`INFORMATION_SCHEMA`.`TABLES` WHERE `TABLE_SCHEMA`=? AND (`ENGINE`='MyISAM' OR `ENGINE` = 'InnoDB' OR `ENGINE` = 'TokuDB')" - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - tables := make([]*core.Table, 0) - for rows.Next() { - table := core.NewEmptyTable() - var name, engine, tableRows, comment string - var autoIncr *string - err = rows.Scan(&name, &engine, &tableRows, &autoIncr, &comment) - if err != nil { - return nil, err - } - - table.Name = name - table.Comment = comment - table.StoreEngine = engine - tables = append(tables, table) - } - return tables, nil -} - -func (db *mysql) GetIndexes(tableName string) (map[string]*core.Index, error) { - args := []interface{}{db.DbName, tableName} - s := "SELECT `INDEX_NAME`, `NON_UNIQUE`, `COLUMN_NAME` FROM `INFORMATION_SCHEMA`.`STATISTICS` WHERE `TABLE_SCHEMA` = ? AND `TABLE_NAME` = ?" - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - indexes := make(map[string]*core.Index, 0) - for rows.Next() { - var indexType int - var indexName, colName, nonUnique string - err = rows.Scan(&indexName, &nonUnique, &colName) - if err != nil { - return nil, err - } - - if indexName == "PRIMARY" { - continue - } - - if "YES" == nonUnique || nonUnique == "1" { - indexType = core.IndexType - } else { - indexType = core.UniqueType - } - - colName = strings.Trim(colName, "` ") - var isRegular bool - if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { - indexName = indexName[5+len(tableName):] - isRegular = true - } - - var index *core.Index - var ok bool - if index, ok = indexes[indexName]; !ok { - index = new(core.Index) - index.IsRegular = isRegular - index.Type = indexType - index.Name = indexName - indexes[indexName] = index - } - index.AddColumn(colName) - } - return indexes, nil -} - -func (db *mysql) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string { - var sql string - sql = "CREATE TABLE IF NOT EXISTS " - if tableName == "" { - tableName = table.Name - } - - sql += db.Quote(tableName) - sql += " (" - - if len(table.ColumnsSeq()) > 0 { - pkList := table.PrimaryKeys - - for _, colName := range table.ColumnsSeq() { - col := table.GetColumn(colName) - if col.IsPrimaryKey && len(pkList) == 1 { - sql += col.String(db) - } else { - sql += col.StringNoPk(db) - } - sql = strings.TrimSpace(sql) - if len(col.Comment) > 0 { - sql += " COMMENT '" + col.Comment + "'" - } - sql += ", " - } - - if len(pkList) > 1 { - sql += "PRIMARY KEY ( " - sql += db.Quote(strings.Join(pkList, db.Quote(","))) - sql += " ), " - } - - sql = sql[:len(sql)-2] - } - sql += ")" - - if storeEngine != "" { - sql += " ENGINE=" + storeEngine - } - - if len(charset) == 0 { - charset = db.URI().Charset - } - if len(charset) != 0 { - sql += " DEFAULT CHARSET " + charset - } - - if db.rowFormat != "" { - sql += " ROW_FORMAT=" + db.rowFormat - } - return sql -} - -func (db *mysql) Filters() []core.Filter { - return []core.Filter{&core.IdFilter{}} -} - -type mymysqlDriver struct { -} - -func (p *mymysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - db := &core.Uri{DbType: core.MYSQL} - - pd := strings.SplitN(dataSourceName, "*", 2) - if len(pd) == 2 { - // Parse protocol part of URI - p := strings.SplitN(pd[0], ":", 2) - if len(p) != 2 { - return nil, errors.New("Wrong protocol part of URI") - } - db.Proto = p[0] - options := strings.Split(p[1], ",") - db.Raddr = options[0] - for _, o := range options[1:] { - kv := strings.SplitN(o, "=", 2) - var k, v string - if len(kv) == 2 { - k, v = kv[0], kv[1] - } else { - k, v = o, "true" - } - switch k { - case "laddr": - db.Laddr = v - case "timeout": - to, err := time.ParseDuration(v) - if err != nil { - return nil, err - } - db.Timeout = to - default: - return nil, errors.New("Unknown option: " + k) - } - } - // Remove protocol part - pd = pd[1:] - } - // Parse database part of URI - dup := strings.SplitN(pd[0], "/", 3) - if len(dup) != 3 { - return nil, errors.New("Wrong database part of URI") - } - db.DbName = dup[0] - db.User = dup[1] - db.Passwd = dup[2] - - return db, nil -} - -type mysqlDriver struct { -} - -func (p *mysqlDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - dsnPattern := regexp.MustCompile( - `^(?:(?P.*?)(?::(?P.*))?@)?` + // [user[:password]@] - `(?:(?P[^\(]*)(?:\((?P[^\)]*)\))?)?` + // [net[(addr)]] - `\/(?P.*?)` + // /dbname - `(?:\?(?P[^\?]*))?$`) // [?param1=value1¶mN=valueN] - matches := dsnPattern.FindStringSubmatch(dataSourceName) - // tlsConfigRegister := make(map[string]*tls.Config) - names := dsnPattern.SubexpNames() - - uri := &core.Uri{DbType: core.MYSQL} - - for i, match := range matches { - switch names[i] { - case "dbname": - uri.DbName = match - case "params": - if len(match) > 0 { - kvs := strings.Split(match, "&") - for _, kv := range kvs { - splits := strings.Split(kv, "=") - if len(splits) == 2 { - switch splits[0] { - case "charset": - uri.Charset = splits[1] - } - } - } - } - - } - } - return uri, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_oracle.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_oracle.go deleted file mode 100644 index 15010ca5a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_oracle.go +++ /dev/null @@ -1,902 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "regexp" - "strconv" - "strings" - - "xorm.io/core" -) - -var ( - oracleReservedWords = map[string]bool{ - "ACCESS": true, - "ACCOUNT": true, - "ACTIVATE": true, - "ADD": true, - "ADMIN": true, - "ADVISE": true, - "AFTER": true, - "ALL": true, - "ALL_ROWS": true, - "ALLOCATE": true, - "ALTER": true, - "ANALYZE": true, - "AND": true, - "ANY": true, - "ARCHIVE": true, - "ARCHIVELOG": true, - "ARRAY": true, - "AS": true, - "ASC": true, - "AT": true, - "AUDIT": true, - "AUTHENTICATED": true, - "AUTHORIZATION": true, - "AUTOEXTEND": true, - "AUTOMATIC": true, - "BACKUP": true, - "BECOME": true, - "BEFORE": true, - "BEGIN": true, - "BETWEEN": true, - "BFILE": true, - "BITMAP": true, - "BLOB": true, - "BLOCK": true, - "BODY": true, - "BY": true, - "CACHE": true, - "CACHE_INSTANCES": true, - "CANCEL": true, - "CASCADE": true, - "CAST": true, - "CFILE": true, - "CHAINED": true, - "CHANGE": true, - "CHAR": true, - "CHAR_CS": true, - "CHARACTER": true, - "CHECK": true, - "CHECKPOINT": true, - "CHOOSE": true, - "CHUNK": true, - "CLEAR": true, - "CLOB": true, - "CLONE": true, - "CLOSE": true, - "CLOSE_CACHED_OPEN_CURSORS": true, - "CLUSTER": true, - "COALESCE": true, - "COLUMN": true, - "COLUMNS": true, - "COMMENT": true, - "COMMIT": true, - "COMMITTED": true, - "COMPATIBILITY": true, - "COMPILE": true, - "COMPLETE": true, - "COMPOSITE_LIMIT": true, - "COMPRESS": true, - "COMPUTE": true, - "CONNECT": true, - "CONNECT_TIME": true, - "CONSTRAINT": true, - "CONSTRAINTS": true, - "CONTENTS": true, - "CONTINUE": true, - "CONTROLFILE": true, - "CONVERT": true, - "COST": true, - "CPU_PER_CALL": true, - "CPU_PER_SESSION": true, - "CREATE": true, - "CURRENT": true, - "CURRENT_SCHEMA": true, - "CURREN_USER": true, - "CURSOR": true, - "CYCLE": true, - "DANGLING": true, - "DATABASE": true, - "DATAFILE": true, - "DATAFILES": true, - "DATAOBJNO": true, - "DATE": true, - "DBA": true, - "DBHIGH": true, - "DBLOW": true, - "DBMAC": true, - "DEALLOCATE": true, - "DEBUG": true, - "DEC": true, - "DECIMAL": true, - "DECLARE": true, - "DEFAULT": true, - "DEFERRABLE": true, - "DEFERRED": true, - "DEGREE": true, - "DELETE": true, - "DEREF": true, - "DESC": true, - "DIRECTORY": true, - "DISABLE": true, - "DISCONNECT": true, - "DISMOUNT": true, - "DISTINCT": true, - "DISTRIBUTED": true, - "DML": true, - "DOUBLE": true, - "DROP": true, - "DUMP": true, - "EACH": true, - "ELSE": true, - "ENABLE": true, - "END": true, - "ENFORCE": true, - "ENTRY": true, - "ESCAPE": true, - "EXCEPT": true, - "EXCEPTIONS": true, - "EXCHANGE": true, - "EXCLUDING": true, - "EXCLUSIVE": true, - "EXECUTE": true, - "EXISTS": true, - "EXPIRE": true, - "EXPLAIN": true, - "EXTENT": true, - "EXTENTS": true, - "EXTERNALLY": true, - "FAILED_LOGIN_ATTEMPTS": true, - "FALSE": true, - "FAST": true, - "FILE": true, - "FIRST_ROWS": true, - "FLAGGER": true, - "FLOAT": true, - "FLOB": true, - "FLUSH": true, - "FOR": true, - "FORCE": true, - "FOREIGN": true, - "FREELIST": true, - "FREELISTS": true, - "FROM": true, - "FULL": true, - "FUNCTION": true, - "GLOBAL": true, - "GLOBALLY": true, - "GLOBAL_NAME": true, - "GRANT": true, - "GROUP": true, - "GROUPS": true, - "HASH": true, - "HASHKEYS": true, - "HAVING": true, - "HEADER": true, - "HEAP": true, - "IDENTIFIED": true, - "IDGENERATORS": true, - "IDLE_TIME": true, - "IF": true, - "IMMEDIATE": true, - "IN": true, - "INCLUDING": true, - "INCREMENT": true, - "INDEX": true, - "INDEXED": true, - "INDEXES": true, - "INDICATOR": true, - "IND_PARTITION": true, - "INITIAL": true, - "INITIALLY": true, - "INITRANS": true, - "INSERT": true, - "INSTANCE": true, - "INSTANCES": true, - "INSTEAD": true, - "INT": true, - "INTEGER": true, - "INTERMEDIATE": true, - "INTERSECT": true, - "INTO": true, - "IS": true, - "ISOLATION": true, - "ISOLATION_LEVEL": true, - "KEEP": true, - "KEY": true, - "KILL": true, - "LABEL": true, - "LAYER": true, - "LESS": true, - "LEVEL": true, - "LIBRARY": true, - "LIKE": true, - "LIMIT": true, - "LINK": true, - "LIST": true, - "LOB": true, - "LOCAL": true, - "LOCK": true, - "LOCKED": true, - "LOG": true, - "LOGFILE": true, - "LOGGING": true, - "LOGICAL_READS_PER_CALL": true, - "LOGICAL_READS_PER_SESSION": true, - "LONG": true, - "MANAGE": true, - "MASTER": true, - "MAX": true, - "MAXARCHLOGS": true, - "MAXDATAFILES": true, - "MAXEXTENTS": true, - "MAXINSTANCES": true, - "MAXLOGFILES": true, - "MAXLOGHISTORY": true, - "MAXLOGMEMBERS": true, - "MAXSIZE": true, - "MAXTRANS": true, - "MAXVALUE": true, - "MIN": true, - "MEMBER": true, - "MINIMUM": true, - "MINEXTENTS": true, - "MINUS": true, - "MINVALUE": true, - "MLSLABEL": true, - "MLS_LABEL_FORMAT": true, - "MODE": true, - "MODIFY": true, - "MOUNT": true, - "MOVE": true, - "MTS_DISPATCHERS": true, - "MULTISET": true, - "NATIONAL": true, - "NCHAR": true, - "NCHAR_CS": true, - "NCLOB": true, - "NEEDED": true, - "NESTED": true, - "NETWORK": true, - "NEW": true, - "NEXT": true, - "NOARCHIVELOG": true, - "NOAUDIT": true, - "NOCACHE": true, - "NOCOMPRESS": true, - "NOCYCLE": true, - "NOFORCE": true, - "NOLOGGING": true, - "NOMAXVALUE": true, - "NOMINVALUE": true, - "NONE": true, - "NOORDER": true, - "NOOVERRIDE": true, - "NOPARALLEL": true, - "NOREVERSE": true, - "NORMAL": true, - "NOSORT": true, - "NOT": true, - "NOTHING": true, - "NOWAIT": true, - "NULL": true, - "NUMBER": true, - "NUMERIC": true, - "NVARCHAR2": true, - "OBJECT": true, - "OBJNO": true, - "OBJNO_REUSE": true, - "OF": true, - "OFF": true, - "OFFLINE": true, - "OID": true, - "OIDINDEX": true, - "OLD": true, - "ON": true, - "ONLINE": true, - "ONLY": true, - "OPCODE": true, - "OPEN": true, - "OPTIMAL": true, - "OPTIMIZER_GOAL": true, - "OPTION": true, - "OR": true, - "ORDER": true, - "ORGANIZATION": true, - "OSLABEL": true, - "OVERFLOW": true, - "OWN": true, - "PACKAGE": true, - "PARALLEL": true, - "PARTITION": true, - "PASSWORD": true, - "PASSWORD_GRACE_TIME": true, - "PASSWORD_LIFE_TIME": true, - "PASSWORD_LOCK_TIME": true, - "PASSWORD_REUSE_MAX": true, - "PASSWORD_REUSE_TIME": true, - "PASSWORD_VERIFY_FUNCTION": true, - "PCTFREE": true, - "PCTINCREASE": true, - "PCTTHRESHOLD": true, - "PCTUSED": true, - "PCTVERSION": true, - "PERCENT": true, - "PERMANENT": true, - "PLAN": true, - "PLSQL_DEBUG": true, - "POST_TRANSACTION": true, - "PRECISION": true, - "PRESERVE": true, - "PRIMARY": true, - "PRIOR": true, - "PRIVATE": true, - "PRIVATE_SGA": true, - "PRIVILEGE": true, - "PRIVILEGES": true, - "PROCEDURE": true, - "PROFILE": true, - "PUBLIC": true, - "PURGE": true, - "QUEUE": true, - "QUOTA": true, - "RANGE": true, - "RAW": true, - "RBA": true, - "READ": true, - "READUP": true, - "REAL": true, - "REBUILD": true, - "RECOVER": true, - "RECOVERABLE": true, - "RECOVERY": true, - "REF": true, - "REFERENCES": true, - "REFERENCING": true, - "REFRESH": true, - "RENAME": true, - "REPLACE": true, - "RESET": true, - "RESETLOGS": true, - "RESIZE": true, - "RESOURCE": true, - "RESTRICTED": true, - "RETURN": true, - "RETURNING": true, - "REUSE": true, - "REVERSE": true, - "REVOKE": true, - "ROLE": true, - "ROLES": true, - "ROLLBACK": true, - "ROW": true, - "ROWID": true, - "ROWNUM": true, - "ROWS": true, - "RULE": true, - "SAMPLE": true, - "SAVEPOINT": true, - "SB4": true, - "SCAN_INSTANCES": true, - "SCHEMA": true, - "SCN": true, - "SCOPE": true, - "SD_ALL": true, - "SD_INHIBIT": true, - "SD_SHOW": true, - "SEGMENT": true, - "SEG_BLOCK": true, - "SEG_FILE": true, - "SELECT": true, - "SEQUENCE": true, - "SERIALIZABLE": true, - "SESSION": true, - "SESSION_CACHED_CURSORS": true, - "SESSIONS_PER_USER": true, - "SET": true, - "SHARE": true, - "SHARED": true, - "SHARED_POOL": true, - "SHRINK": true, - "SIZE": true, - "SKIP": true, - "SKIP_UNUSABLE_INDEXES": true, - "SMALLINT": true, - "SNAPSHOT": true, - "SOME": true, - "SORT": true, - "SPECIFICATION": true, - "SPLIT": true, - "SQL_TRACE": true, - "STANDBY": true, - "START": true, - "STATEMENT_ID": true, - "STATISTICS": true, - "STOP": true, - "STORAGE": true, - "STORE": true, - "STRUCTURE": true, - "SUCCESSFUL": true, - "SWITCH": true, - "SYS_OP_ENFORCE_NOT_NULL$": true, - "SYS_OP_NTCIMG$": true, - "SYNONYM": true, - "SYSDATE": true, - "SYSDBA": true, - "SYSOPER": true, - "SYSTEM": true, - "TABLE": true, - "TABLES": true, - "TABLESPACE": true, - "TABLESPACE_NO": true, - "TABNO": true, - "TEMPORARY": true, - "THAN": true, - "THE": true, - "THEN": true, - "THREAD": true, - "TIMESTAMP": true, - "TIME": true, - "TO": true, - "TOPLEVEL": true, - "TRACE": true, - "TRACING": true, - "TRANSACTION": true, - "TRANSITIONAL": true, - "TRIGGER": true, - "TRIGGERS": true, - "TRUE": true, - "TRUNCATE": true, - "TX": true, - "TYPE": true, - "UB2": true, - "UBA": true, - "UID": true, - "UNARCHIVED": true, - "UNDO": true, - "UNION": true, - "UNIQUE": true, - "UNLIMITED": true, - "UNLOCK": true, - "UNRECOVERABLE": true, - "UNTIL": true, - "UNUSABLE": true, - "UNUSED": true, - "UPDATABLE": true, - "UPDATE": true, - "USAGE": true, - "USE": true, - "USER": true, - "USING": true, - "VALIDATE": true, - "VALIDATION": true, - "VALUE": true, - "VALUES": true, - "VARCHAR": true, - "VARCHAR2": true, - "VARYING": true, - "VIEW": true, - "WHEN": true, - "WHENEVER": true, - "WHERE": true, - "WITH": true, - "WITHOUT": true, - "WORK": true, - "WRITE": true, - "WRITEDOWN": true, - "WRITEUP": true, - "XID": true, - "YEAR": true, - "ZONE": true, - } -) - -type oracle struct { - core.Base -} - -func (db *oracle) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { - return db.Base.Init(d, db, uri, drivername, dataSourceName) -} - -func (db *oracle) SqlType(c *core.Column) string { - var res string - switch t := c.SQLType.Name; t { - case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt, core.Bool, core.Serial, core.BigSerial: - res = "NUMBER" - case core.Binary, core.VarBinary, core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob, core.Bytea: - return core.Blob - case core.Time, core.DateTime, core.TimeStamp: - res = core.TimeStamp - case core.TimeStampz: - res = "TIMESTAMP WITH TIME ZONE" - case core.Float, core.Double, core.Numeric, core.Decimal: - res = "NUMBER" - case core.Text, core.MediumText, core.LongText, core.Json: - res = "CLOB" - case core.Char, core.Varchar, core.TinyText: - res = "VARCHAR2" - default: - res = t - } - - hasLen1 := (c.Length > 0) - hasLen2 := (c.Length2 > 0) - - if hasLen2 { - res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")" - } else if hasLen1 { - res += "(" + strconv.Itoa(c.Length) + ")" - } - return res -} - -func (db *oracle) AutoIncrStr() string { - return "AUTO_INCREMENT" -} - -func (db *oracle) SupportInsertMany() bool { - return true -} - -func (db *oracle) IsReserved(name string) bool { - _, ok := oracleReservedWords[name] - return ok -} - -func (db *oracle) Quote(name string) string { - return "[" + name + "]" -} - -func (db *oracle) SupportEngine() bool { - return false -} - -func (db *oracle) SupportCharset() bool { - return false -} - -func (db *oracle) SupportDropIfExists() bool { - return false -} - -func (db *oracle) IndexOnTable() bool { - return false -} - -func (db *oracle) DropTableSql(tableName string) string { - return fmt.Sprintf("DROP TABLE `%s`", tableName) -} - -func (db *oracle) CreateTableSql(table *core.Table, tableName, storeEngine, charset string) string { - var sql string - sql = "CREATE TABLE " - if tableName == "" { - tableName = table.Name - } - - sql += db.Quote(tableName) + " (" - - pkList := table.PrimaryKeys - - for _, colName := range table.ColumnsSeq() { - col := table.GetColumn(colName) - /*if col.IsPrimaryKey && len(pkList) == 1 { - sql += col.String(b.dialect) - } else {*/ - sql += col.StringNoPk(db) - // } - sql = strings.TrimSpace(sql) - sql += ", " - } - - if len(pkList) > 0 { - sql += "PRIMARY KEY ( " - sql += db.Quote(strings.Join(pkList, db.Quote(","))) - sql += " ), " - } - - sql = sql[:len(sql)-2] + ")" - if db.SupportEngine() && storeEngine != "" { - sql += " ENGINE=" + storeEngine - } - if db.SupportCharset() { - if len(charset) == 0 { - charset = db.URI().Charset - } - if len(charset) > 0 { - sql += " DEFAULT CHARSET " + charset - } - } - return sql -} - -func (db *oracle) IndexCheckSql(tableName, idxName string) (string, []interface{}) { - args := []interface{}{tableName, idxName} - return `SELECT INDEX_NAME FROM USER_INDEXES ` + - `WHERE TABLE_NAME = :1 AND INDEX_NAME = :2`, args -} - -func (db *oracle) TableCheckSql(tableName string) (string, []interface{}) { - args := []interface{}{tableName} - return `SELECT table_name FROM user_tables WHERE table_name = :1`, args -} - -func (db *oracle) MustDropTable(tableName string) error { - sql, args := db.TableCheckSql(tableName) - db.LogSQL(sql, args) - - rows, err := db.DB().Query(sql, args...) - if err != nil { - return err - } - defer rows.Close() - - if !rows.Next() { - return nil - } - - sql = "Drop Table \"" + tableName + "\"" - db.LogSQL(sql, args) - - _, err = db.DB().Exec(sql) - return err -} - -/*func (db *oracle) ColumnCheckSql(tableName, colName string) (string, []interface{}) { - args := []interface{}{strings.ToUpper(tableName), strings.ToUpper(colName)} - return "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = ?" + - " AND column_name = ?", args -}*/ - -func (db *oracle) IsColumnExist(tableName, colName string) (bool, error) { - args := []interface{}{tableName, colName} - query := "SELECT column_name FROM USER_TAB_COLUMNS WHERE table_name = :1" + - " AND column_name = :2" - db.LogSQL(query, args) - - rows, err := db.DB().Query(query, args...) - if err != nil { - return false, err - } - defer rows.Close() - - if rows.Next() { - return true, nil - } - return false, nil -} - -func (db *oracle) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { - args := []interface{}{tableName} - s := "SELECT column_name,data_default,data_type,data_length,data_precision,data_scale," + - "nullable FROM USER_TAB_COLUMNS WHERE table_name = :1" - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, nil, err - } - defer rows.Close() - - cols := make(map[string]*core.Column) - colSeq := make([]string, 0) - for rows.Next() { - col := new(core.Column) - col.Indexes = make(map[string]int) - - var colName, colDefault, nullable, dataType, dataPrecision, dataScale *string - var dataLen int - - err = rows.Scan(&colName, &colDefault, &dataType, &dataLen, &dataPrecision, - &dataScale, &nullable) - if err != nil { - return nil, nil, err - } - - col.Name = strings.Trim(*colName, `" `) - if colDefault != nil { - col.Default = *colDefault - col.DefaultIsEmpty = false - } - - if *nullable == "Y" { - col.Nullable = true - } else { - col.Nullable = false - } - - var ignore bool - - var dt string - var len1, len2 int - dts := strings.Split(*dataType, "(") - dt = dts[0] - if len(dts) > 1 { - lens := strings.Split(dts[1][:len(dts[1])-1], ",") - if len(lens) > 1 { - len1, _ = strconv.Atoi(lens[0]) - len2, _ = strconv.Atoi(lens[1]) - } else { - len1, _ = strconv.Atoi(lens[0]) - } - } - - switch dt { - case "VARCHAR2": - col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: len1, DefaultLength2: len2} - case "NVARCHAR2": - col.SQLType = core.SQLType{Name: core.NVarchar, DefaultLength: len1, DefaultLength2: len2} - case "TIMESTAMP WITH TIME ZONE": - col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0} - case "NUMBER": - col.SQLType = core.SQLType{Name: core.Double, DefaultLength: len1, DefaultLength2: len2} - case "LONG", "LONG RAW": - col.SQLType = core.SQLType{Name: core.Text, DefaultLength: 0, DefaultLength2: 0} - case "RAW": - col.SQLType = core.SQLType{Name: core.Binary, DefaultLength: 0, DefaultLength2: 0} - case "ROWID": - col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 18, DefaultLength2: 0} - case "AQ$_SUBSCRIBERS": - ignore = true - default: - col.SQLType = core.SQLType{Name: strings.ToUpper(dt), DefaultLength: len1, DefaultLength2: len2} - } - - if ignore { - continue - } - - if _, ok := core.SqlTypes[col.SQLType.Name]; !ok { - return nil, nil, fmt.Errorf("Unknown colType %v %v", *dataType, col.SQLType) - } - - col.Length = dataLen - - if col.SQLType.IsText() || col.SQLType.IsTime() { - if !col.DefaultIsEmpty { - col.Default = "'" + col.Default + "'" - } - } - cols[col.Name] = col - colSeq = append(colSeq, col.Name) - } - - return colSeq, cols, nil -} - -func (db *oracle) GetTables() ([]*core.Table, error) { - args := []interface{}{} - s := "SELECT table_name FROM user_tables" - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - tables := make([]*core.Table, 0) - for rows.Next() { - table := core.NewEmptyTable() - err = rows.Scan(&table.Name) - if err != nil { - return nil, err - } - - tables = append(tables, table) - } - return tables, nil -} - -func (db *oracle) GetIndexes(tableName string) (map[string]*core.Index, error) { - args := []interface{}{tableName} - s := "SELECT t.column_name,i.uniqueness,i.index_name FROM user_ind_columns t,user_indexes i " + - "WHERE t.index_name = i.index_name and t.table_name = i.table_name and t.table_name =:1" - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - indexes := make(map[string]*core.Index, 0) - for rows.Next() { - var indexType int - var indexName, colName, uniqueness string - - err = rows.Scan(&colName, &uniqueness, &indexName) - if err != nil { - return nil, err - } - - indexName = strings.Trim(indexName, `" `) - - var isRegular bool - if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { - indexName = indexName[5+len(tableName):] - isRegular = true - } - - if uniqueness == "UNIQUE" { - indexType = core.UniqueType - } else { - indexType = core.IndexType - } - - var index *core.Index - var ok bool - if index, ok = indexes[indexName]; !ok { - index = new(core.Index) - index.Type = indexType - index.Name = indexName - index.IsRegular = isRegular - indexes[indexName] = index - } - index.AddColumn(colName) - } - return indexes, nil -} - -func (db *oracle) Filters() []core.Filter { - return []core.Filter{&core.QuoteFilter{}, &core.SeqFilter{Prefix: ":", Start: 1}, &core.IdFilter{}} -} - -type goracleDriver struct { -} - -func (cfg *goracleDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - db := &core.Uri{DbType: core.ORACLE} - dsnPattern := regexp.MustCompile( - `^(?:(?P.*?)(?::(?P.*))?@)?` + // [user[:password]@] - `(?:(?P[^\(]*)(?:\((?P[^\)]*)\))?)?` + // [net[(addr)]] - `\/(?P.*?)` + // /dbname - `(?:\?(?P[^\?]*))?$`) // [?param1=value1¶mN=valueN] - matches := dsnPattern.FindStringSubmatch(dataSourceName) - // tlsConfigRegister := make(map[string]*tls.Config) - names := dsnPattern.SubexpNames() - - for i, match := range matches { - switch names[i] { - case "dbname": - db.DbName = match - } - } - if db.DbName == "" { - return nil, errors.New("dbname is empty") - } - return db, nil -} - -type oci8Driver struct { -} - -// dataSourceName=user/password@ipv4:port/dbname -// dataSourceName=user/password@[ipv6]:port/dbname -func (p *oci8Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - db := &core.Uri{DbType: core.ORACLE} - dsnPattern := regexp.MustCompile( - `^(?P.*)\/(?P.*)@` + // user:password@ - `(?P.*)` + // ip:port - `\/(?P.*)`) // dbname - matches := dsnPattern.FindStringSubmatch(dataSourceName) - names := dsnPattern.SubexpNames() - for i, match := range matches { - switch names[i] { - case "dbname": - db.DbName = match - } - } - if db.DbName == "" { - return nil, errors.New("dbname is empty") - } - return db, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_postgres.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_postgres.go deleted file mode 100644 index ccef3086b..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_postgres.go +++ /dev/null @@ -1,1253 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "net/url" - "strconv" - "strings" - - "xorm.io/core" -) - -// from http://www.postgresql.org/docs/current/static/sql-keywords-appendix.html -var ( - postgresReservedWords = map[string]bool{ - "A": true, - "ABORT": true, - "ABS": true, - "ABSENT": true, - "ABSOLUTE": true, - "ACCESS": true, - "ACCORDING": true, - "ACTION": true, - "ADA": true, - "ADD": true, - "ADMIN": true, - "AFTER": true, - "AGGREGATE": true, - "ALL": true, - "ALLOCATE": true, - "ALSO": true, - "ALTER": true, - "ALWAYS": true, - "ANALYSE": true, - "ANALYZE": true, - "AND": true, - "ANY": true, - "ARE": true, - "ARRAY": true, - "ARRAY_AGG": true, - "ARRAY_MAX_CARDINALITY": true, - "AS": true, - "ASC": true, - "ASENSITIVE": true, - "ASSERTION": true, - "ASSIGNMENT": true, - "ASYMMETRIC": true, - "AT": true, - "ATOMIC": true, - "ATTRIBUTE": true, - "ATTRIBUTES": true, - "AUTHORIZATION": true, - "AVG": true, - "BACKWARD": true, - "BASE64": true, - "BEFORE": true, - "BEGIN": true, - "BEGIN_FRAME": true, - "BEGIN_PARTITION": true, - "BERNOULLI": true, - "BETWEEN": true, - "BIGINT": true, - "BINARY": true, - "BIT": true, - "BIT_LENGTH": true, - "BLOB": true, - "BLOCKED": true, - "BOM": true, - "BOOLEAN": true, - "BOTH": true, - "BREADTH": true, - "BY": true, - "C": true, - "CACHE": true, - "CALL": true, - "CALLED": true, - "CARDINALITY": true, - "CASCADE": true, - "CASCADED": true, - "CASE": true, - "CAST": true, - "CATALOG": true, - "CATALOG_NAME": true, - "CEIL": true, - "CEILING": true, - "CHAIN": true, - "CHAR": true, - "CHARACTER": true, - "CHARACTERISTICS": true, - "CHARACTERS": true, - "CHARACTER_LENGTH": true, - "CHARACTER_SET_CATALOG": true, - "CHARACTER_SET_NAME": true, - "CHARACTER_SET_SCHEMA": true, - "CHAR_LENGTH": true, - "CHECK": true, - "CHECKPOINT": true, - "CLASS": true, - "CLASS_ORIGIN": true, - "CLOB": true, - "CLOSE": true, - "CLUSTER": true, - "COALESCE": true, - "COBOL": true, - "COLLATE": true, - "COLLATION": true, - "COLLATION_CATALOG": true, - "COLLATION_NAME": true, - "COLLATION_SCHEMA": true, - "COLLECT": true, - "COLUMN": true, - "COLUMNS": true, - "COLUMN_NAME": true, - "COMMAND_FUNCTION": true, - "COMMAND_FUNCTION_CODE": true, - "COMMENT": true, - "COMMENTS": true, - "COMMIT": true, - "COMMITTED": true, - "CONCURRENTLY": true, - "CONDITION": true, - "CONDITION_NUMBER": true, - "CONFIGURATION": true, - "CONNECT": true, - "CONNECTION": true, - "CONNECTION_NAME": true, - "CONSTRAINT": true, - "CONSTRAINTS": true, - "CONSTRAINT_CATALOG": true, - "CONSTRAINT_NAME": true, - "CONSTRAINT_SCHEMA": true, - "CONSTRUCTOR": true, - "CONTAINS": true, - "CONTENT": true, - "CONTINUE": true, - "CONTROL": true, - "CONVERSION": true, - "CONVERT": true, - "COPY": true, - "CORR": true, - "CORRESPONDING": true, - "COST": true, - "COUNT": true, - "COVAR_POP": true, - "COVAR_SAMP": true, - "CREATE": true, - "CROSS": true, - "CSV": true, - "CUBE": true, - "CUME_DIST": true, - "CURRENT": true, - "CURRENT_CATALOG": true, - "CURRENT_DATE": true, - "CURRENT_DEFAULT_TRANSFORM_GROUP": true, - "CURRENT_PATH": true, - "CURRENT_ROLE": true, - "CURRENT_ROW": true, - "CURRENT_SCHEMA": true, - "CURRENT_TIME": true, - "CURRENT_TIMESTAMP": true, - "CURRENT_TRANSFORM_GROUP_FOR_TYPE": true, - "CURRENT_USER": true, - "CURSOR": true, - "CURSOR_NAME": true, - "CYCLE": true, - "DATA": true, - "DATABASE": true, - "DATALINK": true, - "DATE": true, - "DATETIME_INTERVAL_CODE": true, - "DATETIME_INTERVAL_PRECISION": true, - "DAY": true, - "DB": true, - "DEALLOCATE": true, - "DEC": true, - "DECIMAL": true, - "DECLARE": true, - "DEFAULT": true, - "DEFAULTS": true, - "DEFERRABLE": true, - "DEFERRED": true, - "DEFINED": true, - "DEFINER": true, - "DEGREE": true, - "DELETE": true, - "DELIMITER": true, - "DELIMITERS": true, - "DENSE_RANK": true, - "DEPTH": true, - "DEREF": true, - "DERIVED": true, - "DESC": true, - "DESCRIBE": true, - "DESCRIPTOR": true, - "DETERMINISTIC": true, - "DIAGNOSTICS": true, - "DICTIONARY": true, - "DISABLE": true, - "DISCARD": true, - "DISCONNECT": true, - "DISPATCH": true, - "DISTINCT": true, - "DLNEWCOPY": true, - "DLPREVIOUSCOPY": true, - "DLURLCOMPLETE": true, - "DLURLCOMPLETEONLY": true, - "DLURLCOMPLETEWRITE": true, - "DLURLPATH": true, - "DLURLPATHONLY": true, - "DLURLPATHWRITE": true, - "DLURLSCHEME": true, - "DLURLSERVER": true, - "DLVALUE": true, - "DO": true, - "DOCUMENT": true, - "DOMAIN": true, - "DOUBLE": true, - "DROP": true, - "DYNAMIC": true, - "DYNAMIC_FUNCTION": true, - "DYNAMIC_FUNCTION_CODE": true, - "EACH": true, - "ELEMENT": true, - "ELSE": true, - "EMPTY": true, - "ENABLE": true, - "ENCODING": true, - "ENCRYPTED": true, - "END": true, - "END-EXEC": true, - "END_FRAME": true, - "END_PARTITION": true, - "ENFORCED": true, - "ENUM": true, - "EQUALS": true, - "ESCAPE": true, - "EVENT": true, - "EVERY": true, - "EXCEPT": true, - "EXCEPTION": true, - "EXCLUDE": true, - "EXCLUDING": true, - "EXCLUSIVE": true, - "EXEC": true, - "EXECUTE": true, - "EXISTS": true, - "EXP": true, - "EXPLAIN": true, - "EXPRESSION": true, - "EXTENSION": true, - "EXTERNAL": true, - "EXTRACT": true, - "FALSE": true, - "FAMILY": true, - "FETCH": true, - "FILE": true, - "FILTER": true, - "FINAL": true, - "FIRST": true, - "FIRST_VALUE": true, - "FLAG": true, - "FLOAT": true, - "FLOOR": true, - "FOLLOWING": true, - "FOR": true, - "FORCE": true, - "FOREIGN": true, - "FORTRAN": true, - "FORWARD": true, - "FOUND": true, - "FRAME_ROW": true, - "FREE": true, - "FREEZE": true, - "FROM": true, - "FS": true, - "FULL": true, - "FUNCTION": true, - "FUNCTIONS": true, - "FUSION": true, - "G": true, - "GENERAL": true, - "GENERATED": true, - "GET": true, - "GLOBAL": true, - "GO": true, - "GOTO": true, - "GRANT": true, - "GRANTED": true, - "GREATEST": true, - "GROUP": true, - "GROUPING": true, - "GROUPS": true, - "HANDLER": true, - "HAVING": true, - "HEADER": true, - "HEX": true, - "HIERARCHY": true, - "HOLD": true, - "HOUR": true, - "ID": true, - "IDENTITY": true, - "IF": true, - "IGNORE": true, - "ILIKE": true, - "IMMEDIATE": true, - "IMMEDIATELY": true, - "IMMUTABLE": true, - "IMPLEMENTATION": true, - "IMPLICIT": true, - "IMPORT": true, - "IN": true, - "INCLUDING": true, - "INCREMENT": true, - "INDENT": true, - "INDEX": true, - "INDEXES": true, - "INDICATOR": true, - "INHERIT": true, - "INHERITS": true, - "INITIALLY": true, - "INLINE": true, - "INNER": true, - "INOUT": true, - "INPUT": true, - "INSENSITIVE": true, - "INSERT": true, - "INSTANCE": true, - "INSTANTIABLE": true, - "INSTEAD": true, - "INT": true, - "INTEGER": true, - "INTEGRITY": true, - "INTERSECT": true, - "INTERSECTION": true, - "INTERVAL": true, - "INTO": true, - "INVOKER": true, - "IS": true, - "ISNULL": true, - "ISOLATION": true, - "JOIN": true, - "K": true, - "KEY": true, - "KEY_MEMBER": true, - "KEY_TYPE": true, - "LABEL": true, - "LAG": true, - "LANGUAGE": true, - "LARGE": true, - "LAST": true, - "LAST_VALUE": true, - "LATERAL": true, - "LC_COLLATE": true, - "LC_CTYPE": true, - "LEAD": true, - "LEADING": true, - "LEAKPROOF": true, - "LEAST": true, - "LEFT": true, - "LENGTH": true, - "LEVEL": true, - "LIBRARY": true, - "LIKE": true, - "LIKE_REGEX": true, - "LIMIT": true, - "LINK": true, - "LISTEN": true, - "LN": true, - "LOAD": true, - "LOCAL": true, - "LOCALTIME": true, - "LOCALTIMESTAMP": true, - "LOCATION": true, - "LOCATOR": true, - "LOCK": true, - "LOWER": true, - "M": true, - "MAP": true, - "MAPPING": true, - "MATCH": true, - "MATCHED": true, - "MATERIALIZED": true, - "MAX": true, - "MAXVALUE": true, - "MAX_CARDINALITY": true, - "MEMBER": true, - "MERGE": true, - "MESSAGE_LENGTH": true, - "MESSAGE_OCTET_LENGTH": true, - "MESSAGE_TEXT": true, - "METHOD": true, - "MIN": true, - "MINUTE": true, - "MINVALUE": true, - "MOD": true, - "MODE": true, - "MODIFIES": true, - "MODULE": true, - "MONTH": true, - "MORE": true, - "MOVE": true, - "MULTISET": true, - "MUMPS": true, - "NAME": true, - "NAMES": true, - "NAMESPACE": true, - "NATIONAL": true, - "NATURAL": true, - "NCHAR": true, - "NCLOB": true, - "NESTING": true, - "NEW": true, - "NEXT": true, - "NFC": true, - "NFD": true, - "NFKC": true, - "NFKD": true, - "NIL": true, - "NO": true, - "NONE": true, - "NORMALIZE": true, - "NORMALIZED": true, - "NOT": true, - "NOTHING": true, - "NOTIFY": true, - "NOTNULL": true, - "NOWAIT": true, - "NTH_VALUE": true, - "NTILE": true, - "NULL": true, - "NULLABLE": true, - "NULLIF": true, - "NULLS": true, - "NUMBER": true, - "NUMERIC": true, - "OBJECT": true, - "OCCURRENCES_REGEX": true, - "OCTETS": true, - "OCTET_LENGTH": true, - "OF": true, - "OFF": true, - "OFFSET": true, - "OIDS": true, - "OLD": true, - "ON": true, - "ONLY": true, - "OPEN": true, - "OPERATOR": true, - "OPTION": true, - "OPTIONS": true, - "OR": true, - "ORDER": true, - "ORDERING": true, - "ORDINALITY": true, - "OTHERS": true, - "OUT": true, - "OUTER": true, - "OUTPUT": true, - "OVER": true, - "OVERLAPS": true, - "OVERLAY": true, - "OVERRIDING": true, - "OWNED": true, - "OWNER": true, - "P": true, - "PAD": true, - "PARAMETER": true, - "PARAMETER_MODE": true, - "PARAMETER_NAME": true, - "PARAMETER_ORDINAL_POSITION": true, - "PARAMETER_SPECIFIC_CATALOG": true, - "PARAMETER_SPECIFIC_NAME": true, - "PARAMETER_SPECIFIC_SCHEMA": true, - "PARSER": true, - "PARTIAL": true, - "PARTITION": true, - "PASCAL": true, - "PASSING": true, - "PASSTHROUGH": true, - "PASSWORD": true, - "PATH": true, - "PERCENT": true, - "PERCENTILE_CONT": true, - "PERCENTILE_DISC": true, - "PERCENT_RANK": true, - "PERIOD": true, - "PERMISSION": true, - "PLACING": true, - "PLANS": true, - "PLI": true, - "PORTION": true, - "POSITION": true, - "POSITION_REGEX": true, - "POWER": true, - "PRECEDES": true, - "PRECEDING": true, - "PRECISION": true, - "PREPARE": true, - "PREPARED": true, - "PRESERVE": true, - "PRIMARY": true, - "PRIOR": true, - "PRIVILEGES": true, - "PROCEDURAL": true, - "PROCEDURE": true, - "PROGRAM": true, - "PUBLIC": true, - "QUOTE": true, - "RANGE": true, - "RANK": true, - "READ": true, - "READS": true, - "REAL": true, - "REASSIGN": true, - "RECHECK": true, - "RECOVERY": true, - "RECURSIVE": true, - "REF": true, - "REFERENCES": true, - "REFERENCING": true, - "REFRESH": true, - "REGR_AVGX": true, - "REGR_AVGY": true, - "REGR_COUNT": true, - "REGR_INTERCEPT": true, - "REGR_R2": true, - "REGR_SLOPE": true, - "REGR_SXX": true, - "REGR_SXY": true, - "REGR_SYY": true, - "REINDEX": true, - "RELATIVE": true, - "RELEASE": true, - "RENAME": true, - "REPEATABLE": true, - "REPLACE": true, - "REPLICA": true, - "REQUIRING": true, - "RESET": true, - "RESPECT": true, - "RESTART": true, - "RESTORE": true, - "RESTRICT": true, - "RESULT": true, - "RETURN": true, - "RETURNED_CARDINALITY": true, - "RETURNED_LENGTH": true, - "RETURNED_OCTET_LENGTH": true, - "RETURNED_SQLSTATE": true, - "RETURNING": true, - "RETURNS": true, - "REVOKE": true, - "RIGHT": true, - "ROLE": true, - "ROLLBACK": true, - "ROLLUP": true, - "ROUTINE": true, - "ROUTINE_CATALOG": true, - "ROUTINE_NAME": true, - "ROUTINE_SCHEMA": true, - "ROW": true, - "ROWS": true, - "ROW_COUNT": true, - "ROW_NUMBER": true, - "RULE": true, - "SAVEPOINT": true, - "SCALE": true, - "SCHEMA": true, - "SCHEMA_NAME": true, - "SCOPE": true, - "SCOPE_CATALOG": true, - "SCOPE_NAME": true, - "SCOPE_SCHEMA": true, - "SCROLL": true, - "SEARCH": true, - "SECOND": true, - "SECTION": true, - "SECURITY": true, - "SELECT": true, - "SELECTIVE": true, - "SELF": true, - "SENSITIVE": true, - "SEQUENCE": true, - "SEQUENCES": true, - "SERIALIZABLE": true, - "SERVER": true, - "SERVER_NAME": true, - "SESSION": true, - "SESSION_USER": true, - "SET": true, - "SETOF": true, - "SETS": true, - "SHARE": true, - "SHOW": true, - "SIMILAR": true, - "SIMPLE": true, - "SIZE": true, - "SMALLINT": true, - "SNAPSHOT": true, - "SOME": true, - "SOURCE": true, - "SPACE": true, - "SPECIFIC": true, - "SPECIFICTYPE": true, - "SPECIFIC_NAME": true, - "SQL": true, - "SQLCODE": true, - "SQLERROR": true, - "SQLEXCEPTION": true, - "SQLSTATE": true, - "SQLWARNING": true, - "SQRT": true, - "STABLE": true, - "STANDALONE": true, - "START": true, - "STATE": true, - "STATEMENT": true, - "STATIC": true, - "STATISTICS": true, - "STDDEV_POP": true, - "STDDEV_SAMP": true, - "STDIN": true, - "STDOUT": true, - "STORAGE": true, - "STRICT": true, - "STRIP": true, - "STRUCTURE": true, - "STYLE": true, - "SUBCLASS_ORIGIN": true, - "SUBMULTISET": true, - "SUBSTRING": true, - "SUBSTRING_REGEX": true, - "SUCCEEDS": true, - "SUM": true, - "SYMMETRIC": true, - "SYSID": true, - "SYSTEM": true, - "SYSTEM_TIME": true, - "SYSTEM_USER": true, - "T": true, - "TABLE": true, - "TABLES": true, - "TABLESAMPLE": true, - "TABLESPACE": true, - "TABLE_NAME": true, - "TEMP": true, - "TEMPLATE": true, - "TEMPORARY": true, - "TEXT": true, - "THEN": true, - "TIES": true, - "TIME": true, - "TIMESTAMP": true, - "TIMEZONE_HOUR": true, - "TIMEZONE_MINUTE": true, - "TO": true, - "TOKEN": true, - "TOP_LEVEL_COUNT": true, - "TRAILING": true, - "TRANSACTION": true, - "TRANSACTIONS_COMMITTED": true, - "TRANSACTIONS_ROLLED_BACK": true, - "TRANSACTION_ACTIVE": true, - "TRANSFORM": true, - "TRANSFORMS": true, - "TRANSLATE": true, - "TRANSLATE_REGEX": true, - "TRANSLATION": true, - "TREAT": true, - "TRIGGER": true, - "TRIGGER_CATALOG": true, - "TRIGGER_NAME": true, - "TRIGGER_SCHEMA": true, - "TRIM": true, - "TRIM_ARRAY": true, - "TRUE": true, - "TRUNCATE": true, - "TRUSTED": true, - "TYPE": true, - "TYPES": true, - "UESCAPE": true, - "UNBOUNDED": true, - "UNCOMMITTED": true, - "UNDER": true, - "UNENCRYPTED": true, - "UNION": true, - "UNIQUE": true, - "UNKNOWN": true, - "UNLINK": true, - "UNLISTEN": true, - "UNLOGGED": true, - "UNNAMED": true, - "UNNEST": true, - "UNTIL": true, - "UNTYPED": true, - "UPDATE": true, - "UPPER": true, - "URI": true, - "USAGE": true, - "USER": true, - "USER_DEFINED_TYPE_CATALOG": true, - "USER_DEFINED_TYPE_CODE": true, - "USER_DEFINED_TYPE_NAME": true, - "USER_DEFINED_TYPE_SCHEMA": true, - "USING": true, - "VACUUM": true, - "VALID": true, - "VALIDATE": true, - "VALIDATOR": true, - "VALUE": true, - "VALUES": true, - "VALUE_OF": true, - "VARBINARY": true, - "VARCHAR": true, - "VARIADIC": true, - "VARYING": true, - "VAR_POP": true, - "VAR_SAMP": true, - "VERBOSE": true, - "VERSION": true, - "VERSIONING": true, - "VIEW": true, - "VOLATILE": true, - "WHEN": true, - "WHENEVER": true, - "WHERE": true, - "WHITESPACE": true, - "WIDTH_BUCKET": true, - "WINDOW": true, - "WITH": true, - "WITHIN": true, - "WITHOUT": true, - "WORK": true, - "WRAPPER": true, - "WRITE": true, - "XML": true, - "XMLAGG": true, - "XMLATTRIBUTES": true, - "XMLBINARY": true, - "XMLCAST": true, - "XMLCOMMENT": true, - "XMLCONCAT": true, - "XMLDECLARATION": true, - "XMLDOCUMENT": true, - "XMLELEMENT": true, - "XMLEXISTS": true, - "XMLFOREST": true, - "XMLITERATE": true, - "XMLNAMESPACES": true, - "XMLPARSE": true, - "XMLPI": true, - "XMLQUERY": true, - "XMLROOT": true, - "XMLSCHEMA": true, - "XMLSERIALIZE": true, - "XMLTABLE": true, - "XMLTEXT": true, - "XMLVALIDATE": true, - "YEAR": true, - "YES": true, - "ZONE": true, - } - - // DefaultPostgresSchema default postgres schema - DefaultPostgresSchema = "public" -) - -const postgresPublicSchema = "public" - -type postgres struct { - core.Base -} - -func (db *postgres) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { - err := db.Base.Init(d, db, uri, drivername, dataSourceName) - if err != nil { - return err - } - if db.Schema == "" { - db.Schema = DefaultPostgresSchema - } - return nil -} - -func (db *postgres) SqlType(c *core.Column) string { - var res string - switch t := c.SQLType.Name; t { - case core.TinyInt: - res = core.SmallInt - return res - case core.Bit: - res = core.Boolean - return res - case core.MediumInt, core.Int, core.Integer: - if c.IsAutoIncrement { - return core.Serial - } - return core.Integer - case core.BigInt: - if c.IsAutoIncrement { - return core.BigSerial - } - return core.BigInt - case core.Serial, core.BigSerial: - c.IsAutoIncrement = true - c.Nullable = false - res = t - case core.Binary, core.VarBinary: - return core.Bytea - case core.DateTime: - res = core.TimeStamp - case core.TimeStampz: - return "timestamp with time zone" - case core.Float: - res = core.Real - case core.TinyText, core.MediumText, core.LongText: - res = core.Text - case core.NVarchar: - res = core.Varchar - case core.Uuid: - return core.Uuid - case core.Blob, core.TinyBlob, core.MediumBlob, core.LongBlob: - return core.Bytea - case core.Double: - return "DOUBLE PRECISION" - default: - if c.IsAutoIncrement { - return core.Serial - } - res = t - } - - if strings.EqualFold(res, "bool") { - // for bool, we don't need length information - return res - } - hasLen1 := (c.Length > 0) - hasLen2 := (c.Length2 > 0) - - if hasLen2 { - res += "(" + strconv.Itoa(c.Length) + "," + strconv.Itoa(c.Length2) + ")" - } else if hasLen1 { - res += "(" + strconv.Itoa(c.Length) + ")" - } - return res -} - -func (db *postgres) SupportInsertMany() bool { - return true -} - -func (db *postgres) IsReserved(name string) bool { - _, ok := postgresReservedWords[name] - return ok -} - -func (db *postgres) Quote(name string) string { - name = strings.Replace(name, ".", `"."`, -1) - return "\"" + name + "\"" -} - -func (db *postgres) AutoIncrStr() string { - return "" -} - -func (db *postgres) SupportEngine() bool { - return false -} - -func (db *postgres) SupportCharset() bool { - return false -} - -func (db *postgres) IndexOnTable() bool { - return false -} - -func (db *postgres) IndexCheckSql(tableName, idxName string) (string, []interface{}) { - if len(db.Schema) == 0 { - args := []interface{}{tableName, idxName} - return `SELECT indexname FROM pg_indexes WHERE tablename = ? AND indexname = ?`, args - } - - args := []interface{}{db.Schema, tableName, idxName} - return `SELECT indexname FROM pg_indexes ` + - `WHERE schemaname = ? AND tablename = ? AND indexname = ?`, args -} - -func (db *postgres) TableCheckSql(tableName string) (string, []interface{}) { - if len(db.Schema) == 0 { - args := []interface{}{tableName} - return `SELECT tablename FROM pg_tables WHERE tablename = ?`, args - } - - args := []interface{}{db.Schema, tableName} - return `SELECT tablename FROM pg_tables WHERE schemaname = ? AND tablename = ?`, args -} - -func (db *postgres) ModifyColumnSql(tableName string, col *core.Column) string { - if len(db.Schema) == 0 { - return fmt.Sprintf("alter table %s ALTER COLUMN %s TYPE %s", - tableName, col.Name, db.SqlType(col)) - } - return fmt.Sprintf("alter table %s.%s ALTER COLUMN %s TYPE %s", - db.Schema, tableName, col.Name, db.SqlType(col)) -} - -func (db *postgres) DropIndexSql(tableName string, index *core.Index) string { - quote := db.Quote - idxName := index.Name - - tableName = strings.Replace(tableName, `"`, "", -1) - tableName = strings.Replace(tableName, `.`, "_", -1) - - if !strings.HasPrefix(idxName, "UQE_") && - !strings.HasPrefix(idxName, "IDX_") { - if index.Type == core.UniqueType { - idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name) - } else { - idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name) - } - } - if db.Uri.Schema != "" { - idxName = db.Uri.Schema + "." + idxName - } - return fmt.Sprintf("DROP INDEX %v", quote(idxName)) -} - -func (db *postgres) IsColumnExist(tableName, colName string) (bool, error) { - args := []interface{}{db.Schema, tableName, colName} - query := "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = $1 AND table_name = $2" + - " AND column_name = $3" - if len(db.Schema) == 0 { - args = []interface{}{tableName, colName} - query = "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = $1" + - " AND column_name = $2" - } - db.LogSQL(query, args) - - rows, err := db.DB().Query(query, args...) - if err != nil { - return false, err - } - defer rows.Close() - - return rows.Next(), nil -} - -func (db *postgres) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { - args := []interface{}{tableName} - s := `SELECT column_name, column_default, is_nullable, data_type, character_maximum_length, - CASE WHEN p.contype = 'p' THEN true ELSE false END AS primarykey, - CASE WHEN p.contype = 'u' THEN true ELSE false END AS uniquekey -FROM pg_attribute f - JOIN pg_class c ON c.oid = f.attrelid JOIN pg_type t ON t.oid = f.atttypid - LEFT JOIN pg_attrdef d ON d.adrelid = c.oid AND d.adnum = f.attnum - LEFT JOIN pg_namespace n ON n.oid = c.relnamespace - LEFT JOIN pg_constraint p ON p.conrelid = c.oid AND f.attnum = ANY (p.conkey) - LEFT JOIN pg_class AS g ON p.confrelid = g.oid - LEFT JOIN INFORMATION_SCHEMA.COLUMNS s ON s.column_name=f.attname AND c.relname=s.table_name -WHERE c.relkind = 'r'::char AND c.relname = $1%s AND f.attnum > 0 ORDER BY f.attnum;` - - var f string - if len(db.Schema) != 0 { - args = append(args, db.Schema) - f = " AND s.table_schema = $2" - } - s = fmt.Sprintf(s, f) - - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, nil, err - } - defer rows.Close() - - cols := make(map[string]*core.Column) - colSeq := make([]string, 0) - - for rows.Next() { - col := new(core.Column) - col.Indexes = make(map[string]int) - - var colName, isNullable, dataType string - var maxLenStr, colDefault *string - var isPK, isUnique bool - err = rows.Scan(&colName, &colDefault, &isNullable, &dataType, &maxLenStr, &isPK, &isUnique) - if err != nil { - return nil, nil, err - } - - // fmt.Println(args, colName, isNullable, dataType, maxLenStr, colDefault, isPK, isUnique) - var maxLen int - if maxLenStr != nil { - maxLen, err = strconv.Atoi(*maxLenStr) - if err != nil { - return nil, nil, err - } - } - - col.Name = strings.Trim(colName, `" `) - - if colDefault != nil { - col.Default = *colDefault - col.DefaultIsEmpty = false - if strings.HasPrefix(col.Default, "nextval(") { - col.IsAutoIncrement = true - } - } else { - col.DefaultIsEmpty = true - } - - if isPK { - col.IsPrimaryKey = true - } - - col.Nullable = (isNullable == "YES") - - switch dataType { - case "character varying", "character": - col.SQLType = core.SQLType{Name: core.Varchar, DefaultLength: 0, DefaultLength2: 0} - case "timestamp without time zone": - col.SQLType = core.SQLType{Name: core.DateTime, DefaultLength: 0, DefaultLength2: 0} - case "timestamp with time zone": - col.SQLType = core.SQLType{Name: core.TimeStampz, DefaultLength: 0, DefaultLength2: 0} - case "double precision": - col.SQLType = core.SQLType{Name: core.Double, DefaultLength: 0, DefaultLength2: 0} - case "boolean": - col.SQLType = core.SQLType{Name: core.Bool, DefaultLength: 0, DefaultLength2: 0} - case "time without time zone": - col.SQLType = core.SQLType{Name: core.Time, DefaultLength: 0, DefaultLength2: 0} - case "oid": - col.SQLType = core.SQLType{Name: core.BigInt, DefaultLength: 0, DefaultLength2: 0} - default: - col.SQLType = core.SQLType{Name: strings.ToUpper(dataType), DefaultLength: 0, DefaultLength2: 0} - } - if _, ok := core.SqlTypes[col.SQLType.Name]; !ok { - return nil, nil, fmt.Errorf("Unknown colType: %v", dataType) - } - - col.Length = maxLen - - if !col.DefaultIsEmpty { - if col.SQLType.IsText() { - if strings.HasSuffix(col.Default, "::character varying") { - col.Default = strings.TrimRight(col.Default, "::character varying") - } else if !strings.HasPrefix(col.Default, "'") { - col.Default = "'" + col.Default + "'" - } - } else if col.SQLType.IsTime() { - if strings.HasSuffix(col.Default, "::timestamp without time zone") { - col.Default = strings.TrimRight(col.Default, "::timestamp without time zone") - } - } - } - cols[col.Name] = col - colSeq = append(colSeq, col.Name) - } - - return colSeq, cols, nil -} - -func (db *postgres) GetTables() ([]*core.Table, error) { - args := []interface{}{} - s := "SELECT tablename FROM pg_tables" - if len(db.Schema) != 0 { - args = append(args, db.Schema) - s = s + " WHERE schemaname = $1" - } - - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - tables := make([]*core.Table, 0) - for rows.Next() { - table := core.NewEmptyTable() - var name string - err = rows.Scan(&name) - if err != nil { - return nil, err - } - table.Name = name - tables = append(tables, table) - } - return tables, nil -} - -func getIndexColName(indexdef string) []string { - var colNames []string - - cs := strings.Split(indexdef, "(") - for _, v := range strings.Split(strings.Split(cs[1], ")")[0], ",") { - colNames = append(colNames, strings.Split(strings.TrimLeft(v, " "), " ")[0]) - } - - return colNames -} - -func (db *postgres) GetIndexes(tableName string) (map[string]*core.Index, error) { - args := []interface{}{tableName} - s := fmt.Sprintf("SELECT indexname, indexdef FROM pg_indexes WHERE tablename=$1") - if len(db.Schema) != 0 { - args = append(args, db.Schema) - s = s + " AND schemaname=$2" - } - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - indexes := make(map[string]*core.Index, 0) - for rows.Next() { - var indexType int - var indexName, indexdef string - var colNames []string - err = rows.Scan(&indexName, &indexdef) - if err != nil { - return nil, err - } - indexName = strings.Trim(indexName, `" `) - if strings.HasSuffix(indexName, "_pkey") { - continue - } - if strings.HasPrefix(indexdef, "CREATE UNIQUE INDEX") { - indexType = core.UniqueType - } else { - indexType = core.IndexType - } - colNames = getIndexColName(indexdef) - var isRegular bool - if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { - newIdxName := indexName[5+len(tableName):] - isRegular = true - if newIdxName != "" { - indexName = newIdxName - } - } - - index := &core.Index{Name: indexName, Type: indexType, Cols: make([]string, 0)} - for _, colName := range colNames { - index.Cols = append(index.Cols, strings.Trim(colName, `" `)) - } - index.IsRegular = isRegular - indexes[index.Name] = index - } - return indexes, nil -} - -func (db *postgres) Filters() []core.Filter { - return []core.Filter{&core.IdFilter{}, &core.QuoteFilter{}, &core.SeqFilter{Prefix: "$", Start: 1}} -} - -type pqDriver struct { -} - -type values map[string]string - -func (vs values) Set(k, v string) { - vs[k] = v -} - -func (vs values) Get(k string) (v string) { - return vs[k] -} - -func parseURL(connstr string) (string, error) { - u, err := url.Parse(connstr) - if err != nil { - return "", err - } - - if u.Scheme != "postgresql" && u.Scheme != "postgres" { - return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) - } - - escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`) - - if u.Path != "" { - return escaper.Replace(u.Path[1:]), nil - } - - return "", nil -} - -func parseOpts(name string, o values) error { - if len(name) == 0 { - return fmt.Errorf("invalid options: %s", name) - } - - name = strings.TrimSpace(name) - - ps := strings.Split(name, " ") - for _, p := range ps { - kv := strings.Split(p, "=") - if len(kv) < 2 { - return fmt.Errorf("invalid option: %q", p) - } - o.Set(kv[0], kv[1]) - } - - return nil -} - -func (p *pqDriver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - db := &core.Uri{DbType: core.POSTGRES} - var err error - - if strings.HasPrefix(dataSourceName, "postgresql://") || strings.HasPrefix(dataSourceName, "postgres://") { - db.DbName, err = parseURL(dataSourceName) - if err != nil { - return nil, err - } - } else { - o := make(values) - err = parseOpts(dataSourceName, o) - if err != nil { - return nil, err - } - - db.DbName = o.Get("dbname") - } - - if db.DbName == "" { - return nil, errors.New("dbname is empty") - } - - return db, nil -} - -type pqDriverPgx struct { - pqDriver -} - -func (pgx *pqDriverPgx) Parse(driverName, dataSourceName string) (*core.Uri, error) { - // Remove the leading characters for driver to work - if len(dataSourceName) >= 9 && dataSourceName[0] == 0 { - dataSourceName = dataSourceName[9:] - } - return pgx.pqDriver.Parse(driverName, dataSourceName) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_sqlite3.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_sqlite3.go deleted file mode 100644 index 0a290f3c4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/dialect_sqlite3.go +++ /dev/null @@ -1,492 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "errors" - "fmt" - "regexp" - "strings" - - "xorm.io/core" -) - -var ( - sqlite3ReservedWords = map[string]bool{ - "ABORT": true, - "ACTION": true, - "ADD": true, - "AFTER": true, - "ALL": true, - "ALTER": true, - "ANALYZE": true, - "AND": true, - "AS": true, - "ASC": true, - "ATTACH": true, - "AUTOINCREMENT": true, - "BEFORE": true, - "BEGIN": true, - "BETWEEN": true, - "BY": true, - "CASCADE": true, - "CASE": true, - "CAST": true, - "CHECK": true, - "COLLATE": true, - "COLUMN": true, - "COMMIT": true, - "CONFLICT": true, - "CONSTRAINT": true, - "CREATE": true, - "CROSS": true, - "CURRENT_DATE": true, - "CURRENT_TIME": true, - "CURRENT_TIMESTAMP": true, - "DATABASE": true, - "DEFAULT": true, - "DEFERRABLE": true, - "DEFERRED": true, - "DELETE": true, - "DESC": true, - "DETACH": true, - "DISTINCT": true, - "DROP": true, - "EACH": true, - "ELSE": true, - "END": true, - "ESCAPE": true, - "EXCEPT": true, - "EXCLUSIVE": true, - "EXISTS": true, - "EXPLAIN": true, - "FAIL": true, - "FOR": true, - "FOREIGN": true, - "FROM": true, - "FULL": true, - "GLOB": true, - "GROUP": true, - "HAVING": true, - "IF": true, - "IGNORE": true, - "IMMEDIATE": true, - "IN": true, - "INDEX": true, - "INDEXED": true, - "INITIALLY": true, - "INNER": true, - "INSERT": true, - "INSTEAD": true, - "INTERSECT": true, - "INTO": true, - "IS": true, - "ISNULL": true, - "JOIN": true, - "KEY": true, - "LEFT": true, - "LIKE": true, - "LIMIT": true, - "MATCH": true, - "NATURAL": true, - "NO": true, - "NOT": true, - "NOTNULL": true, - "NULL": true, - "OF": true, - "OFFSET": true, - "ON": true, - "OR": true, - "ORDER": true, - "OUTER": true, - "PLAN": true, - "PRAGMA": true, - "PRIMARY": true, - "QUERY": true, - "RAISE": true, - "RECURSIVE": true, - "REFERENCES": true, - "REGEXP": true, - "REINDEX": true, - "RELEASE": true, - "RENAME": true, - "REPLACE": true, - "RESTRICT": true, - "RIGHT": true, - "ROLLBACK": true, - "ROW": true, - "SAVEPOINT": true, - "SELECT": true, - "SET": true, - "TABLE": true, - "TEMP": true, - "TEMPORARY": true, - "THEN": true, - "TO": true, - "TRANSACTI": true, - "TRIGGER": true, - "UNION": true, - "UNIQUE": true, - "UPDATE": true, - "USING": true, - "VACUUM": true, - "VALUES": true, - "VIEW": true, - "VIRTUAL": true, - "WHEN": true, - "WHERE": true, - "WITH": true, - "WITHOUT": true, - } -) - -type sqlite3 struct { - core.Base -} - -func (db *sqlite3) Init(d *core.DB, uri *core.Uri, drivername, dataSourceName string) error { - return db.Base.Init(d, db, uri, drivername, dataSourceName) -} - -func (db *sqlite3) SqlType(c *core.Column) string { - switch t := c.SQLType.Name; t { - case core.Bool: - if c.Default == "true" { - c.Default = "1" - } else if c.Default == "false" { - c.Default = "0" - } - return core.Integer - case core.Date, core.DateTime, core.TimeStamp, core.Time: - return core.DateTime - case core.TimeStampz: - return core.Text - case core.Char, core.Varchar, core.NVarchar, core.TinyText, - core.Text, core.MediumText, core.LongText, core.Json: - return core.Text - case core.Bit, core.TinyInt, core.SmallInt, core.MediumInt, core.Int, core.Integer, core.BigInt: - return core.Integer - case core.Float, core.Double, core.Real: - return core.Real - case core.Decimal, core.Numeric: - return core.Numeric - case core.TinyBlob, core.Blob, core.MediumBlob, core.LongBlob, core.Bytea, core.Binary, core.VarBinary: - return core.Blob - case core.Serial, core.BigSerial: - c.IsPrimaryKey = true - c.IsAutoIncrement = true - c.Nullable = false - return core.Integer - default: - return t - } -} - -func (db *sqlite3) FormatBytes(bs []byte) string { - return fmt.Sprintf("X'%x'", bs) -} - -func (db *sqlite3) SupportInsertMany() bool { - return true -} - -func (db *sqlite3) IsReserved(name string) bool { - _, ok := sqlite3ReservedWords[name] - return ok -} - -func (db *sqlite3) Quote(name string) string { - return "`" + name + "`" -} - -func (db *sqlite3) AutoIncrStr() string { - return "AUTOINCREMENT" -} - -func (db *sqlite3) SupportEngine() bool { - return false -} - -func (db *sqlite3) SupportCharset() bool { - return false -} - -func (db *sqlite3) IndexOnTable() bool { - return false -} - -func (db *sqlite3) IndexCheckSql(tableName, idxName string) (string, []interface{}) { - args := []interface{}{idxName} - return "SELECT name FROM sqlite_master WHERE type='index' and name = ?", args -} - -func (db *sqlite3) TableCheckSql(tableName string) (string, []interface{}) { - args := []interface{}{tableName} - return "SELECT name FROM sqlite_master WHERE type='table' and name = ?", args -} - -func (db *sqlite3) DropIndexSql(tableName string, index *core.Index) string { - // var unique string - quote := db.Quote - idxName := index.Name - - if !strings.HasPrefix(idxName, "UQE_") && - !strings.HasPrefix(idxName, "IDX_") { - if index.Type == core.UniqueType { - idxName = fmt.Sprintf("UQE_%v_%v", tableName, index.Name) - } else { - idxName = fmt.Sprintf("IDX_%v_%v", tableName, index.Name) - } - } - return fmt.Sprintf("DROP INDEX %v", quote(idxName)) -} - -func (db *sqlite3) ForUpdateSql(query string) string { - return query -} - -/*func (db *sqlite3) ColumnCheckSql(tableName, colName string) (string, []interface{}) { - args := []interface{}{tableName} - sql := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))" - return sql, args -}*/ - -func (db *sqlite3) IsColumnExist(tableName, colName string) (bool, error) { - args := []interface{}{tableName} - query := "SELECT name FROM sqlite_master WHERE type='table' and name = ? and ((sql like '%`" + colName + "`%') or (sql like '%[" + colName + "]%'))" - db.LogSQL(query, args) - rows, err := db.DB().Query(query, args...) - if err != nil { - return false, err - } - defer rows.Close() - - if rows.Next() { - return true, nil - } - return false, nil -} - -// splitColStr splits a sqlite col strings as fields -func splitColStr(colStr string) []string { - colStr = strings.TrimSpace(colStr) - var results = make([]string, 0, 10) - var lastIdx int - var hasC, hasQuote bool - for i, c := range colStr { - if c == ' ' && !hasQuote { - if hasC { - results = append(results, colStr[lastIdx:i]) - hasC = false - } - } else { - if c == '\'' { - hasQuote = !hasQuote - } - if !hasC { - lastIdx = i - } - hasC = true - if i == len(colStr)-1 { - results = append(results, colStr[lastIdx:i+1]) - } - } - } - return results -} - -func parseString(colStr string) (*core.Column, error) { - fields := splitColStr(colStr) - col := new(core.Column) - col.Indexes = make(map[string]int) - col.Nullable = true - col.DefaultIsEmpty = true - - for idx, field := range fields { - if idx == 0 { - col.Name = strings.Trim(strings.Trim(field, "`[] "), `"`) - continue - } else if idx == 1 { - col.SQLType = core.SQLType{Name: field, DefaultLength: 0, DefaultLength2: 0} - continue - } - switch field { - case "PRIMARY": - col.IsPrimaryKey = true - case "AUTOINCREMENT": - col.IsAutoIncrement = true - case "NULL": - if fields[idx-1] == "NOT" { - col.Nullable = false - } else { - col.Nullable = true - } - case "DEFAULT": - col.Default = fields[idx+1] - col.DefaultIsEmpty = false - } - } - return col, nil -} - -func (db *sqlite3) GetColumns(tableName string) ([]string, map[string]*core.Column, error) { - args := []interface{}{tableName} - s := "SELECT sql FROM sqlite_master WHERE type='table' and name = ?" - db.LogSQL(s, args) - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, nil, err - } - defer rows.Close() - - var name string - for rows.Next() { - err = rows.Scan(&name) - if err != nil { - return nil, nil, err - } - break - } - - if name == "" { - return nil, nil, errors.New("no table named " + tableName) - } - - nStart := strings.Index(name, "(") - nEnd := strings.LastIndex(name, ")") - reg := regexp.MustCompile(`[^\(,\)]*(\([^\(]*\))?`) - colCreates := reg.FindAllString(name[nStart+1:nEnd], -1) - cols := make(map[string]*core.Column) - colSeq := make([]string, 0) - - for _, colStr := range colCreates { - reg = regexp.MustCompile(`,\s`) - colStr = reg.ReplaceAllString(colStr, ",") - if strings.HasPrefix(strings.TrimSpace(colStr), "PRIMARY KEY") { - parts := strings.Split(strings.TrimSpace(colStr), "(") - if len(parts) == 2 { - pkCols := strings.Split(strings.TrimRight(strings.TrimSpace(parts[1]), ")"), ",") - for _, pk := range pkCols { - if col, ok := cols[strings.Trim(strings.TrimSpace(pk), "`")]; ok { - col.IsPrimaryKey = true - } - } - } - continue - } - - col, err := parseString(colStr) - if err != nil { - return colSeq, cols, err - } - - cols[col.Name] = col - colSeq = append(colSeq, col.Name) - } - return colSeq, cols, nil -} - -func (db *sqlite3) GetTables() ([]*core.Table, error) { - args := []interface{}{} - s := "SELECT name FROM sqlite_master WHERE type='table'" - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - tables := make([]*core.Table, 0) - for rows.Next() { - table := core.NewEmptyTable() - err = rows.Scan(&table.Name) - if err != nil { - return nil, err - } - if table.Name == "sqlite_sequence" { - continue - } - tables = append(tables, table) - } - return tables, nil -} - -func (db *sqlite3) GetIndexes(tableName string) (map[string]*core.Index, error) { - args := []interface{}{tableName} - s := "SELECT sql FROM sqlite_master WHERE type='index' and tbl_name = ?" - db.LogSQL(s, args) - - rows, err := db.DB().Query(s, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - indexes := make(map[string]*core.Index, 0) - for rows.Next() { - var tmpSQL sql.NullString - err = rows.Scan(&tmpSQL) - if err != nil { - return nil, err - } - - if !tmpSQL.Valid { - continue - } - sql := tmpSQL.String - - index := new(core.Index) - nNStart := strings.Index(sql, "INDEX") - nNEnd := strings.Index(sql, "ON") - if nNStart == -1 || nNEnd == -1 { - continue - } - - indexName := strings.Trim(sql[nNStart+6:nNEnd], "` []") - var isRegular bool - if strings.HasPrefix(indexName, "IDX_"+tableName) || strings.HasPrefix(indexName, "UQE_"+tableName) { - index.Name = indexName[5+len(tableName):] - isRegular = true - } else { - index.Name = indexName - } - - if strings.HasPrefix(sql, "CREATE UNIQUE INDEX") { - index.Type = core.UniqueType - } else { - index.Type = core.IndexType - } - - nStart := strings.Index(sql, "(") - nEnd := strings.Index(sql, ")") - colIndexes := strings.Split(sql[nStart+1:nEnd], ",") - - index.Cols = make([]string, 0) - for _, col := range colIndexes { - index.Cols = append(index.Cols, strings.Trim(col, "` []")) - } - index.IsRegular = isRegular - indexes[index.Name] = index - } - - return indexes, nil -} - -func (db *sqlite3) Filters() []core.Filter { - return []core.Filter{&core.IdFilter{}} -} - -type sqlite3Driver struct { -} - -func (p *sqlite3Driver) Parse(driverName, dataSourceName string) (*core.Uri, error) { - if strings.Contains(dataSourceName, "?") { - dataSourceName = dataSourceName[:strings.Index(dataSourceName, "?")] - } - - return &core.Uri{DbType: core.SQLITE, DbName: dataSourceName}, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/doc.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/doc.go deleted file mode 100644 index a687e6947..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/doc.go +++ /dev/null @@ -1,184 +0,0 @@ -// Copyright 2013 - 2016 The XORM Authors. All rights reserved. -// Use of this source code is governed by a BSD -// license that can be found in the LICENSE file. - -/* - -Package xorm is a simple and powerful ORM for Go. - -Installation - -Make sure you have installed Go 1.6+ and then: - - go get github.com/go-xorm/xorm - -Create Engine - -Firstly, we should new an engine for a database - - engine, err := xorm.NewEngine(driverName, dataSourceName) - -Method NewEngine's parameters is the same as sql.Open. It depends -drivers' implementation. -Generally, one engine for an application is enough. You can set it as package variable. - -Raw Methods - -XORM also support raw SQL execution: - -1. query a SQL string, the returned results is []map[string][]byte - - results, err := engine.Query("select * from user") - -2. execute a SQL string, the returned results - - affected, err := engine.Exec("update user set .... where ...") - -ORM Methods - -There are 8 major ORM methods and many helpful methods to use to operate database. - -1. Insert one or multiple records to database - - affected, err := engine.Insert(&struct) - // INSERT INTO struct () values () - affected, err := engine.Insert(&struct1, &struct2) - // INSERT INTO struct1 () values () - // INSERT INTO struct2 () values () - affected, err := engine.Insert(&sliceOfStruct) - // INSERT INTO struct () values (),(),() - affected, err := engine.Insert(&struct1, &sliceOfStruct2) - // INSERT INTO struct1 () values () - // INSERT INTO struct2 () values (),(),() - -2. Query one record or one variable from database - - has, err := engine.Get(&user) - // SELECT * FROM user LIMIT 1 - - var id int64 - has, err := engine.Table("user").Where("name = ?", name).Get(&id) - // SELECT id FROM user WHERE name = ? LIMIT 1 - -3. Query multiple records from database - - var sliceOfStructs []Struct - err := engine.Find(&sliceOfStructs) - // SELECT * FROM user - - var mapOfStructs = make(map[int64]Struct) - err := engine.Find(&mapOfStructs) - // SELECT * FROM user - - var int64s []int64 - err := engine.Table("user").Cols("id").Find(&int64s) - // SELECT id FROM user - -4. Query multiple records and record by record handle, there two methods, one is Iterate, -another is Rows - - err := engine.Iterate(...) - // SELECT * FROM user - - rows, err := engine.Rows(...) - // SELECT * FROM user - defer rows.Close() - bean := new(Struct) - for rows.Next() { - err = rows.Scan(bean) - } - -5. Update one or more records - - affected, err := engine.ID(...).Update(&user) - // UPDATE user SET ... - -6. Delete one or more records, Delete MUST has condition - - affected, err := engine.Where(...).Delete(&user) - // DELETE FROM user Where ... - -7. Count records - - counts, err := engine.Count(&user) - // SELECT count(*) AS total FROM user - - counts, err := engine.SQL("select count(*) FROM user").Count() - // select count(*) FROM user - -8. Sum records - - sumFloat64, err := engine.Sum(&user, "id") - // SELECT sum(id) from user - - sumFloat64s, err := engine.Sums(&user, "id1", "id2") - // SELECT sum(id1), sum(id2) from user - - sumInt64s, err := engine.SumsInt(&user, "id1", "id2") - // SELECT sum(id1), sum(id2) from user - -Conditions - -The above 8 methods could use with condition methods chainable. -Attention: the above 8 methods should be the last chainable method. - -1. ID, In - - engine.ID(1).Get(&user) // for single primary key - // SELECT * FROM user WHERE id = 1 - engine.ID(core.PK{1, 2}).Get(&user) // for composite primary keys - // SELECT * FROM user WHERE id1 = 1 AND id2 = 2 - engine.In("id", 1, 2, 3).Find(&users) - // SELECT * FROM user WHERE id IN (1, 2, 3) - engine.In("id", []int{1, 2, 3}).Find(&users) - // SELECT * FROM user WHERE id IN (1, 2, 3) - -2. Where, And, Or - - engine.Where().And().Or().Find() - // SELECT * FROM user WHERE (.. AND ..) OR ... - -3. OrderBy, Asc, Desc - - engine.Asc().Desc().Find() - // SELECT * FROM user ORDER BY .. ASC, .. DESC - engine.OrderBy().Find() - // SELECT * FROM user ORDER BY .. - -4. Limit, Top - - engine.Limit().Find() - // SELECT * FROM user LIMIT .. OFFSET .. - engine.Top(5).Find() - // SELECT TOP 5 * FROM user // for mssql - // SELECT * FROM user LIMIT .. OFFSET 0 //for other databases - -5. SQL, let you custom SQL - - var users []User - engine.SQL("select * from user").Find(&users) - -6. Cols, Omit, Distinct - - var users []*User - engine.Cols("col1, col2").Find(&users) - // SELECT col1, col2 FROM user - engine.Cols("col1", "col2").Where().Update(user) - // UPDATE user set col1 = ?, col2 = ? Where ... - engine.Omit("col1").Find(&users) - // SELECT col2, col3 FROM user - engine.Omit("col1").Insert(&user) - // INSERT INTO table (non-col1) VALUES () - engine.Distinct("col1").Find(&users) - // SELECT DISTINCT col1 FROM user - -7. Join, GroupBy, Having - - engine.GroupBy("name").Having("name='xlw'").Find(&users) - //SELECT * FROM user GROUP BY name HAVING name='xlw' - engine.Join("LEFT", "userdetail", "user.id=userdetail.id").Find(&users) - //SELECT * FROM user LEFT JOIN userdetail ON user.id=userdetail.id - -More usage, please visit http://xorm.io/docs -*/ -package xorm diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/docs/images/cache_design.graffle b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/docs/images/cache_design.graffle deleted file mode 100644 index 5b7c487b7..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/docs/images/cache_design.graffle +++ /dev/null @@ -1,2295 +0,0 @@ - - - - - ActiveLayerIndex - 0 - ApplicationVersion - - com.omnigroup.OmniGrafflePro - 139.16.0.171715 - - AutoAdjust - - BackgroundGraphic - - Bounds - {{0, 0}, {771, 554.18930041152259}} - Class - SolidGraphic - ID - 2 - Style - - fill - - Color - - b - 0.989303 - g - 0.907286 - r - 0.795377 - - FillType - 2 - GradientAngle - 78 - GradientColor - - b - 1 - g - 0.854588 - r - 0.623912 - - MiddleColor - - b - 1 - g - 0.856844 - r - 0.43695 - - TrippleBlend - YES - - shadow - - Draws - NO - - stroke - - Draws - NO - - - - BaseZoom - 0 - CanvasOrigin - {0, 0} - CanvasSize - {771, 554.18930041152259} - ColumnAlign - 1 - ColumnSpacing - 36 - CreationDate - 2013-09-29 07:57:57 +0000 - Creator - Lunny Xiao - DisplayScale - 1.000 cm = 1.000 cm - FileType - flat - GraphDocumentVersion - 8 - GraphicsList - - - Bounds - {{409.89504441572683, 415.64570506990464}, {104.42639923095703, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 30 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 .\ -.\ -.\ -} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{276.44083898205287, 413.07252538018992}, {112.36092376708984, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 29 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 .\ -.\ -.} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{409.89504441572689, 337.17180246145824}, {104.42639923095703, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 28 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 user-2:User\{\}} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{274.32251833907753, 322.94787397618234}, {112.36092376708984, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 27 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 select id from tb3:[2,5]} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{406.08888702072045, 256.42244420026987}, {104.42639923095703, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 25 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 user-2:User\{\}} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{406.08888302813585, 187.47137690331695}, {104.42639923095703, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 24 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 table-1:Table\{\}} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{406.08887903555114, 118.52029512620169}, {104.42639923095703, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 23 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 user-1:User\{\}} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{556.54055354053583, 325.93280718390133}, {124.41892177446698, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 22 - Shape - Rectangle - Style - - fill - - Color - - b - 0.793851 - g - 0.625208 - r - 0.562982 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.639673 - g - 0.450584 - r - 0.381079 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 Del(k, v)} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{556.54055354053583, 240.81081643580876}, {124.41892177446698, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 21 - Shape - Rectangle - Style - - fill - - Color - - b - 0.793851 - g - 0.625208 - r - 0.562982 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.639673 - g - 0.450584 - r - 0.381079 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 Put(k, v)} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{556.54054526129187, 150.52220626433376}, {124.41893005371094, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 20 - Shape - Rectangle - Style - - fill - - Color - - b - 0.793851 - g - 0.625208 - r - 0.562982 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.639673 - g - 0.450584 - r - 0.381079 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 Get(k, v)} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{276.44083898205287, 214.72973288487913}, {112.36092376708984, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 19 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 select id from tb2:[2,5]} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{274.32251963877655, 117.18245433711769}, {112.36092376708984, 68.777008056640625}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 18 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 select id from tb1:[1,2,3]} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{103.00000194954862, 30.108108889738791}, {80, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 14 - Shape - Rectangle - Style - - fill - - Color - - b - 0.776486 - g - 0.588495 - r - 0.670497 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.618021 - g - 0.412924 - r - 0.50312 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset134 STHeitiSC-Light;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 SQL} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{532.04631600645348, 25.096524339927051}, {166.93052673339844, 79.447883605957031}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - Size - 18 - - ID - 13 - Shape - Rectangle - Style - - fill - - Color - - b - 0.793851 - g - 0.625208 - r - 0.562982 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.639673 - g - 0.450584 - r - 0.381079 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;\f1\fnil\fcharset134 STHeitiSC-Light;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf0 Cache\ - -\f1 Store} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{298.9845516069733, 37.412179328792348}, {173.03089904785156, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.8 - g - 0.8 - r - 0.8 - - Font - Verdana - Size - 18 - - ID - 17 - Shape - Rectangle - Style - - fill - - Color - - b - 0.6 - g - 0.6 - r - 0.6 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.4 - g - 0.4 - r - 0.4 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.590997 - g - 0.18677 - r - 0.567819 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red204\green204\blue204;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 LRUCacher} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{99.822519035537013, 333.12161552787364}, {88, 51}} - Class - ShapedGraphic - FontInfo - - Color - - archive - - YnBsaXN0MDDUAQIDBAUGBwpZJGFyY2hpdmVy - WCR2ZXJzaW9uVCR0b3BYJG9iamVjdHNfEA9O - U0tleWVkQXJjaGl2ZXISAAGGoNEICVRyb290 - gAGlCwwVGR5VJG51bGzUDQ4PEBESExRfEBJO - U0N1c3RvbUNvbG9yU3BhY2VXTlNXaGl0ZVxO - U0NvbG9yU3BhY2VWJGNsYXNzgAJCMAAQA4AE - 0hYQFxhUTlNJRBACgAPSGhscD1gkY2xhc3Nl - c1okY2xhc3NuYW1log8dWE5TT2JqZWN00hob - HyCiIB1XTlNDb2xvcggRGyQpMkRJTFFTWV9o - fYWSmZueoKKnrK6wtb7JzNXa3QAAAAAAAAEB - AAAAAAAAACEAAAAAAAAAAAAAAAAAAADl - - b - 0 - g - 0 - r - 0 - - Font - Verdana - NSKern - 0.0 - Size - 15 - - ID - 12 - Magnets - - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - fill - - Color - - b - 0.806569 - g - 0.806569 - r - 0.806569 - - FillType - 2 - GradientAngle - 90 - GradientColor - - w - 0.653285 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.2 - g - 0.2 - r - 0.2 - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\fs30 \cf0 \expnd0\expndtw0\kerning0 -Delet\ -SQL} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{97.118322659032714, 226.09466078541047}, {88, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0 - g - 0 - r - 0.501961 - - Font - Verdana - NSKern - 0.0 - Size - 15 - - ID - 15 - Magnets - - {1, 0} - {-1, 0} - - Shape - Rectangle - Style - - fill - - Color - - b - 0 - g - 0.389485 - r - 1 - - FillType - 3 - GradientCenter - {-0.34285700000000002, -0.114286} - GradientColor - - b - 0 - g - 0.495748 - r - 1 - - MiddleColor - - b - 0 - g - 0.887657 - r - 1 - - MiddleFraction - 0.6269841194152832 - TrippleBlend - YES - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.2 - g - 0.2 - r - 0.2 - - Draws - NO - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red128\green0\blue0;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\qc - -\f0\fs30 \cf2 \expnd0\expndtw0\kerning0 -Update\ -SQL} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - Bounds - {{103, 123.08108395608006}, {80, 51}} - Class - ShapedGraphic - FontInfo - - Color - - b - 0.821332 - g - 0.672602 - r - 0.928374 - - Font - Verdana - Size - 18 - - ID - 16 - Shape - Rectangle - Style - - fill - - Color - - b - 0.436973 - g - 0.155566 - r - 0.758999 - - FillType - 2 - GradientAngle - 90 - GradientColor - - b - 0.25098 - g - 0 - r - 0.501961 - - - shadow - - Beneath - YES - Color - - a - 0.15 - b - 0 - g - 0 - r - 0 - - Fuzziness - 0.0 - ShadowVector - {2, 2} - - stroke - - Color - - b - 0.511421 - g - 0.637255 - r - 0.120867 - - Draws - NO - Width - 2 - - - Text - - Text - {\rtf1\ansi\ansicpg936\cocoartf1187\cocoasubrtf390 -\cocoascreenfonts1{\fonttbl\f0\fnil\fcharset134 STHeitiSC-Light;\f1\fnil\fcharset0 Verdana;} -{\colortbl;\red255\green255\blue255;\red237\green172\blue209;} -\pard\tx560\tx1120\tx1680\tx2240\tx2800\tx3360\tx3920\tx4480\tx5040\tx5600\tx6160\tx6720\pardirnatural\qc - -\f0\fs36 \cf2 select -\f1 -\f0 SQL} - VerticalPad - 0 - - TextRelativeArea - {{0.10000000000000001, 0.14999999999999999}, {0.80000000000000004, 0.69999999999999996}} - - - GridInfo - - GuidesLocked - NO - GuidesVisible - YES - HPages - 2 - ImageCounter - 3 - KeepToScale - - Layers - - - Lock - NO - Name - 图层 1 - Print - YES - View - YES - - - LayoutInfo - - Animate - NO - AutoLayout - 2 - circoMinDist - 18 - circoSeparation - 0.0 - layoutEngine - neato - neatoLineLength - 0.92083334922790527 - neatoSeparation - 0.0 - twopiSeparation - 0.0 - - LinksVisible - NO - MagnetsVisible - NO - MasterSheets - - ModificationDate - 2013-09-29 08:24:57 +0000 - Modifier - Lunny Xiao - NotesVisible - NO - Orientation - 2 - OriginVisible - NO - OutlineStyle - Brainstorming/Clouds - PageBreaks - NO - PrintInfo - - NSBottomMargin - - float - 41 - - NSHorizonalPagination - - coded - BAtzdHJlYW10eXBlZIHoA4QBQISEhAhOU051bWJlcgCEhAdOU1ZhbHVlAISECE5TT2JqZWN0AIWEASqEhAFxlwCG - - NSLeftMargin - - float - 18 - - NSPaperSize - - size - {595, 842} - - NSPrintReverseOrientation - - int - 0 - - NSRightMargin - - float - 18 - - NSTopMargin - - float - 18 - - - PrintOnePage - - ReadOnly - NO - RowAlign - 1 - RowSpacing - 36 - SheetTitle - 版面 1 - SmartAlignmentGuidesActive - YES - SmartDistanceGuidesActive - YES - UniqueID - 1 - UseEntirePage - - VPages - 1 - WindowInfo - - CurrentSheet - 0 - ExpandedCanvases - - FitInWindow - - Frame - {{138, 197}, {869, 617}} - ListView - - OutlineWidth - 142 - RightSidebar - - Sidebar - - SidebarWidth - 138 - VisibleRegion - {{1.0591603214876664, 1.0591603214876664}, {770.00955372153339, 553.94084813804955}} - Zoom - 0.94414412975311279 - ZoomValues - - - 版面 1 - 0.0 - 1 - - - - - diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine.go deleted file mode 100644 index 4ed0f77a9..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine.go +++ /dev/null @@ -1,1659 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "bufio" - "bytes" - "context" - "database/sql" - "encoding/gob" - "errors" - "fmt" - "io" - "os" - "reflect" - "strconv" - "strings" - "sync" - "time" - - "xorm.io/builder" - "xorm.io/core" -) - -// Engine is the major struct of xorm, it means a database manager. -// Commonly, an application only need one engine -type Engine struct { - db *core.DB - dialect core.Dialect - - ColumnMapper core.IMapper - TableMapper core.IMapper - TagIdentifier string - Tables map[reflect.Type]*core.Table - - mutex *sync.RWMutex - Cacher core.Cacher - - showSQL bool - showExecTime bool - - logger core.ILogger - TZLocation *time.Location // The timezone of the application - DatabaseTZ *time.Location // The timezone of the database - - disableGlobalCache bool - - tagHandlers map[string]tagHandler - - engineGroup *EngineGroup - - cachers map[string]core.Cacher - cacherLock sync.RWMutex - - defaultContext context.Context -} - -func (engine *Engine) setCacher(tableName string, cacher core.Cacher) { - engine.cacherLock.Lock() - engine.cachers[tableName] = cacher - engine.cacherLock.Unlock() -} - -func (engine *Engine) SetCacher(tableName string, cacher core.Cacher) { - engine.setCacher(tableName, cacher) -} - -func (engine *Engine) getCacher(tableName string) core.Cacher { - var cacher core.Cacher - var ok bool - engine.cacherLock.RLock() - cacher, ok = engine.cachers[tableName] - engine.cacherLock.RUnlock() - if !ok && !engine.disableGlobalCache { - cacher = engine.Cacher - } - return cacher -} - -func (engine *Engine) GetCacher(tableName string) core.Cacher { - return engine.getCacher(tableName) -} - -// BufferSize sets buffer size for iterate -func (engine *Engine) BufferSize(size int) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.BufferSize(size) -} - -// CondDeleted returns the conditions whether a record is soft deleted. -func (engine *Engine) CondDeleted(colName string) builder.Cond { - if engine.dialect.DBType() == core.MSSQL { - return builder.IsNull{colName} - } - return builder.IsNull{colName}.Or(builder.Eq{colName: zeroTime1}) -} - -// ShowSQL show SQL statement or not on logger if log level is great than INFO -func (engine *Engine) ShowSQL(show ...bool) { - engine.logger.ShowSQL(show...) - if len(show) == 0 { - engine.showSQL = true - } else { - engine.showSQL = show[0] - } -} - -// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO -func (engine *Engine) ShowExecTime(show ...bool) { - if len(show) == 0 { - engine.showExecTime = true - } else { - engine.showExecTime = show[0] - } -} - -// Logger return the logger interface -func (engine *Engine) Logger() core.ILogger { - return engine.logger -} - -// SetLogger set the new logger -func (engine *Engine) SetLogger(logger core.ILogger) { - engine.logger = logger - engine.showSQL = logger.IsShowSQL() - engine.dialect.SetLogger(logger) -} - -// SetLogLevel sets the logger level -func (engine *Engine) SetLogLevel(level core.LogLevel) { - engine.logger.SetLevel(level) -} - -// SetDisableGlobalCache disable global cache or not -func (engine *Engine) SetDisableGlobalCache(disable bool) { - if engine.disableGlobalCache != disable { - engine.disableGlobalCache = disable - } -} - -// DriverName return the current sql driver's name -func (engine *Engine) DriverName() string { - return engine.dialect.DriverName() -} - -// DataSourceName return the current connection string -func (engine *Engine) DataSourceName() string { - return engine.dialect.DataSourceName() -} - -// SetMapper set the name mapping rules -func (engine *Engine) SetMapper(mapper core.IMapper) { - engine.SetTableMapper(mapper) - engine.SetColumnMapper(mapper) -} - -// SetTableMapper set the table name mapping rule -func (engine *Engine) SetTableMapper(mapper core.IMapper) { - engine.TableMapper = mapper -} - -// SetColumnMapper set the column name mapping rule -func (engine *Engine) SetColumnMapper(mapper core.IMapper) { - engine.ColumnMapper = mapper -} - -// SupportInsertMany If engine's database support batch insert records like -// "insert into user values (name, age), (name, age)". -// When the return is ture, then engine.Insert(&users) will -// generate batch sql and exeute. -func (engine *Engine) SupportInsertMany() bool { - return engine.dialect.SupportInsertMany() -} - -func (engine *Engine) quoteColumns(columnStr string) string { - columns := strings.Split(columnStr, ",") - for i := 0; i < len(columns); i++ { - columns[i] = engine.Quote(strings.TrimSpace(columns[i])) - } - return strings.Join(columns, ",") -} - -// Quote Use QuoteStr quote the string sql -func (engine *Engine) Quote(value string) string { - value = strings.TrimSpace(value) - if len(value) == 0 { - return value - } - - buf := strings.Builder{} - engine.QuoteTo(&buf, value) - - return buf.String() -} - -// QuoteTo quotes string and writes into the buffer -func (engine *Engine) QuoteTo(buf *strings.Builder, value string) { - if buf == nil { - return - } - - value = strings.TrimSpace(value) - if value == "" { - return - } - - quotePair := engine.dialect.Quote("") - - if value[0] == '`' || len(quotePair) < 2 || value[0] == quotePair[0] { // no quote - _, _ = buf.WriteString(value) - return - } else { - prefix, suffix := quotePair[0], quotePair[1] - - _ = buf.WriteByte(prefix) - for i := 0; i < len(value); i++ { - if value[i] == '.' { - _ = buf.WriteByte(suffix) - _ = buf.WriteByte('.') - _ = buf.WriteByte(prefix) - } else { - _ = buf.WriteByte(value[i]) - } - } - _ = buf.WriteByte(suffix) - } -} - -func (engine *Engine) quote(sql string) string { - return engine.dialect.Quote(sql) -} - -// SqlType will be deprecated, please use SQLType instead -// -// Deprecated: use SQLType instead -func (engine *Engine) SqlType(c *core.Column) string { - return engine.SQLType(c) -} - -// SQLType A simple wrapper to dialect's core.SqlType method -func (engine *Engine) SQLType(c *core.Column) string { - return engine.dialect.SqlType(c) -} - -// AutoIncrStr Database's autoincrement statement -func (engine *Engine) AutoIncrStr() string { - return engine.dialect.AutoIncrStr() -} - -// SetConnMaxLifetime sets the maximum amount of time a connection may be reused. -func (engine *Engine) SetConnMaxLifetime(d time.Duration) { - engine.db.SetConnMaxLifetime(d) -} - -// SetMaxOpenConns is only available for go 1.2+ -func (engine *Engine) SetMaxOpenConns(conns int) { - engine.db.SetMaxOpenConns(conns) -} - -// SetMaxIdleConns set the max idle connections on pool, default is 2 -func (engine *Engine) SetMaxIdleConns(conns int) { - engine.db.SetMaxIdleConns(conns) -} - -// SetDefaultCacher set the default cacher. Xorm's default not enable cacher. -func (engine *Engine) SetDefaultCacher(cacher core.Cacher) { - engine.Cacher = cacher -} - -// GetDefaultCacher returns the default cacher -func (engine *Engine) GetDefaultCacher() core.Cacher { - return engine.Cacher -} - -// NoCache If you has set default cacher, and you want temporilly stop use cache, -// you can use NoCache() -func (engine *Engine) NoCache() *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.NoCache() -} - -// NoCascade If you do not want to auto cascade load object -func (engine *Engine) NoCascade() *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.NoCascade() -} - -// MapCacher Set a table use a special cacher -func (engine *Engine) MapCacher(bean interface{}, cacher core.Cacher) error { - engine.setCacher(engine.TableName(bean, true), cacher) - return nil -} - -// NewDB provides an interface to operate database directly -func (engine *Engine) NewDB() (*core.DB, error) { - return core.OpenDialect(engine.dialect) -} - -// DB return the wrapper of sql.DB -func (engine *Engine) DB() *core.DB { - return engine.db -} - -// Dialect return database dialect -func (engine *Engine) Dialect() core.Dialect { - return engine.dialect -} - -// NewSession New a session -func (engine *Engine) NewSession() *Session { - session := &Session{engine: engine} - session.Init() - return session -} - -// Close the engine -func (engine *Engine) Close() error { - return engine.db.Close() -} - -// Ping tests if database is alive -func (engine *Engine) Ping() error { - session := engine.NewSession() - defer session.Close() - return session.Ping() -} - -// logging sql -func (engine *Engine) logSQL(sqlStr string, sqlArgs ...interface{}) { - if engine.showSQL && !engine.showExecTime { - if len(sqlArgs) > 0 { - engine.logger.Infof("[SQL] %v %#v", sqlStr, sqlArgs) - } else { - engine.logger.Infof("[SQL] %v", sqlStr) - } - } -} - -// Sql provides raw sql input parameter. When you have a complex SQL statement -// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. -// -// Deprecated: use SQL instead. -func (engine *Engine) Sql(querystring string, args ...interface{}) *Session { - return engine.SQL(querystring, args...) -} - -// SQL method let's you manually write raw SQL and operate -// For example: -// -// engine.SQL("select * from user").Find(&users) -// -// This code will execute "select * from user" and set the records to users -func (engine *Engine) SQL(query interface{}, args ...interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.SQL(query, args...) -} - -// NoAutoTime Default if your struct has "created" or "updated" filed tag, the fields -// will automatically be filled with current time when Insert or Update -// invoked. Call NoAutoTime if you dont' want to fill automatically. -func (engine *Engine) NoAutoTime() *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.NoAutoTime() -} - -// NoAutoCondition disable auto generate Where condition from bean or not -func (engine *Engine) NoAutoCondition(no ...bool) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.NoAutoCondition(no...) -} - -func (engine *Engine) loadTableInfo(table *core.Table) error { - colSeq, cols, err := engine.dialect.GetColumns(table.Name) - if err != nil { - return err - } - for _, name := range colSeq { - table.AddColumn(cols[name]) - } - indexes, err := engine.dialect.GetIndexes(table.Name) - if err != nil { - return err - } - table.Indexes = indexes - - for _, index := range indexes { - for _, name := range index.Cols { - if col := table.GetColumn(name); col != nil { - col.Indexes[index.Name] = index.Type - } else { - return fmt.Errorf("Unknown col %s in index %v of table %v, columns %v", name, index.Name, table.Name, table.ColumnsSeq()) - } - } - } - return nil -} - -// DBMetas Retrieve all tables, columns, indexes' informations from database. -func (engine *Engine) DBMetas() ([]*core.Table, error) { - tables, err := engine.dialect.GetTables() - if err != nil { - return nil, err - } - - for _, table := range tables { - if err = engine.loadTableInfo(table); err != nil { - return nil, err - } - } - return tables, nil -} - -// DumpAllToFile dump database all table structs and data to a file -func (engine *Engine) DumpAllToFile(fp string, tp ...core.DbType) error { - f, err := os.Create(fp) - if err != nil { - return err - } - defer f.Close() - return engine.DumpAll(f, tp...) -} - -// DumpAll dump database all table structs and data to w -func (engine *Engine) DumpAll(w io.Writer, tp ...core.DbType) error { - tables, err := engine.DBMetas() - if err != nil { - return err - } - return engine.DumpTables(tables, w, tp...) -} - -// DumpTablesToFile dump specified tables to SQL file. -func (engine *Engine) DumpTablesToFile(tables []*core.Table, fp string, tp ...core.DbType) error { - f, err := os.Create(fp) - if err != nil { - return err - } - defer f.Close() - return engine.DumpTables(tables, f, tp...) -} - -// DumpTables dump specify tables to io.Writer -func (engine *Engine) DumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error { - return engine.dumpTables(tables, w, tp...) -} - -// dumpTables dump database all table structs and data to w with specify db type -func (engine *Engine) dumpTables(tables []*core.Table, w io.Writer, tp ...core.DbType) error { - var dialect core.Dialect - var distDBName string - if len(tp) == 0 { - dialect = engine.dialect - distDBName = string(engine.dialect.DBType()) - } else { - dialect = core.QueryDialect(tp[0]) - if dialect == nil { - return errors.New("Unsupported database type") - } - dialect.Init(nil, engine.dialect.URI(), "", "") - distDBName = string(tp[0]) - } - - _, err := io.WriteString(w, fmt.Sprintf("/*Generated by xorm v%s %s, from %s to %s*/\n\n", - Version, time.Now().In(engine.TZLocation).Format("2006-01-02 15:04:05"), engine.dialect.DBType(), strings.ToUpper(distDBName))) - if err != nil { - return err - } - - for i, table := range tables { - if i > 0 { - _, err = io.WriteString(w, "\n") - if err != nil { - return err - } - } - _, err = io.WriteString(w, dialect.CreateTableSql(table, "", table.StoreEngine, "")+";\n") - if err != nil { - return err - } - for _, index := range table.Indexes { - _, err = io.WriteString(w, dialect.CreateIndexSql(table.Name, index)+";\n") - if err != nil { - return err - } - } - - cols := table.ColumnsSeq() - colNames := engine.dialect.Quote(strings.Join(cols, engine.dialect.Quote(", "))) - destColNames := dialect.Quote(strings.Join(cols, dialect.Quote(", "))) - - rows, err := engine.DB().Query("SELECT " + colNames + " FROM " + engine.Quote(table.Name)) - if err != nil { - return err - } - defer rows.Close() - - for rows.Next() { - dest := make([]interface{}, len(cols)) - err = rows.ScanSlice(&dest) - if err != nil { - return err - } - - _, err = io.WriteString(w, "INSERT INTO "+dialect.Quote(table.Name)+" ("+destColNames+") VALUES (") - if err != nil { - return err - } - - var temp string - for i, d := range dest { - col := table.GetColumn(cols[i]) - if col == nil { - return errors.New("unknow column error") - } - - if d == nil { - temp += ", NULL" - } else if col.SQLType.IsText() || col.SQLType.IsTime() { - var v = fmt.Sprintf("%s", d) - if strings.HasSuffix(v, " +0000 UTC") { - temp += fmt.Sprintf(", '%s'", v[0:len(v)-len(" +0000 UTC")]) - } else { - temp += ", '" + strings.Replace(v, "'", "''", -1) + "'" - } - } else if col.SQLType.IsBlob() { - if reflect.TypeOf(d).Kind() == reflect.Slice { - temp += fmt.Sprintf(", %s", dialect.FormatBytes(d.([]byte))) - } else if reflect.TypeOf(d).Kind() == reflect.String { - temp += fmt.Sprintf(", '%s'", d.(string)) - } - } else if col.SQLType.IsNumeric() { - switch reflect.TypeOf(d).Kind() { - case reflect.Slice: - if col.SQLType.Name == core.Bool { - temp += fmt.Sprintf(", %v", strconv.FormatBool(d.([]byte)[0] != byte('0'))) - } else { - temp += fmt.Sprintf(", %s", string(d.([]byte))) - } - case reflect.Int16, reflect.Int8, reflect.Int32, reflect.Int64, reflect.Int: - if col.SQLType.Name == core.Bool { - temp += fmt.Sprintf(", %v", strconv.FormatBool(reflect.ValueOf(d).Int() > 0)) - } else { - temp += fmt.Sprintf(", %v", d) - } - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - if col.SQLType.Name == core.Bool { - temp += fmt.Sprintf(", %v", strconv.FormatBool(reflect.ValueOf(d).Uint() > 0)) - } else { - temp += fmt.Sprintf(", %v", d) - } - default: - temp += fmt.Sprintf(", %v", d) - } - } else { - s := fmt.Sprintf("%v", d) - if strings.Contains(s, ":") || strings.Contains(s, "-") { - if strings.HasSuffix(s, " +0000 UTC") { - temp += fmt.Sprintf(", '%s'", s[0:len(s)-len(" +0000 UTC")]) - } else { - temp += fmt.Sprintf(", '%s'", s) - } - } else { - temp += fmt.Sprintf(", %s", s) - } - } - } - _, err = io.WriteString(w, temp[2:]+");\n") - if err != nil { - return err - } - } - - // FIXME: Hack for postgres - if string(dialect.DBType()) == core.POSTGRES && table.AutoIncrColumn() != nil { - _, err = io.WriteString(w, "SELECT setval('"+table.Name+"_id_seq', COALESCE((SELECT MAX("+table.AutoIncrColumn().Name+") + 1 FROM "+dialect.Quote(table.Name)+"), 1), false);\n") - if err != nil { - return err - } - } - } - return nil -} - -// Cascade use cascade or not -func (engine *Engine) Cascade(trueOrFalse ...bool) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Cascade(trueOrFalse...) -} - -// Where method provide a condition query -func (engine *Engine) Where(query interface{}, args ...interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Where(query, args...) -} - -// Id will be deprecated, please use ID instead -func (engine *Engine) Id(id interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Id(id) -} - -// ID method provoide a condition as (id) = ? -func (engine *Engine) ID(id interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.ID(id) -} - -// Before apply before Processor, affected bean is passed to closure arg -func (engine *Engine) Before(closures func(interface{})) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Before(closures) -} - -// After apply after insert Processor, affected bean is passed to closure arg -func (engine *Engine) After(closures func(interface{})) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.After(closures) -} - -// Charset set charset when create table, only support mysql now -func (engine *Engine) Charset(charset string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Charset(charset) -} - -// StoreEngine set store engine when create table, only support mysql now -func (engine *Engine) StoreEngine(storeEngine string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.StoreEngine(storeEngine) -} - -// Distinct use for distinct columns. Caution: when you are using cache, -// distinct will not be cached because cache system need id, -// but distinct will not provide id -func (engine *Engine) Distinct(columns ...string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Distinct(columns...) -} - -// Select customerize your select columns or contents -func (engine *Engine) Select(str string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Select(str) -} - -// Cols only use the parameters as select or update columns -func (engine *Engine) Cols(columns ...string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Cols(columns...) -} - -// AllCols indicates that all columns should be use -func (engine *Engine) AllCols() *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.AllCols() -} - -// MustCols specify some columns must use even if they are empty -func (engine *Engine) MustCols(columns ...string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.MustCols(columns...) -} - -// UseBool xorm automatically retrieve condition according struct, but -// if struct has bool field, it will ignore them. So use UseBool -// to tell system to do not ignore them. -// If no parameters, it will use all the bool field of struct, or -// it will use parameters's columns -func (engine *Engine) UseBool(columns ...string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.UseBool(columns...) -} - -// Omit only not use the parameters as select or update columns -func (engine *Engine) Omit(columns ...string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Omit(columns...) -} - -// Nullable set null when column is zero-value and nullable for update -func (engine *Engine) Nullable(columns ...string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Nullable(columns...) -} - -// In will generate "column IN (?, ?)" -func (engine *Engine) In(column string, args ...interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.In(column, args...) -} - -// NotIn will generate "column NOT IN (?, ?)" -func (engine *Engine) NotIn(column string, args ...interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.NotIn(column, args...) -} - -// Incr provides a update string like "column = column + ?" -func (engine *Engine) Incr(column string, arg ...interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Incr(column, arg...) -} - -// Decr provides a update string like "column = column - ?" -func (engine *Engine) Decr(column string, arg ...interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Decr(column, arg...) -} - -// SetExpr provides a update string like "column = {expression}" -func (engine *Engine) SetExpr(column string, expression interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.SetExpr(column, expression) -} - -// Table temporarily change the Get, Find, Update's table -func (engine *Engine) Table(tableNameOrBean interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Table(tableNameOrBean) -} - -// Alias set the table alias -func (engine *Engine) Alias(alias string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Alias(alias) -} - -// Limit will generate "LIMIT start, limit" -func (engine *Engine) Limit(limit int, start ...int) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Limit(limit, start...) -} - -// Desc will generate "ORDER BY column1 DESC, column2 DESC" -func (engine *Engine) Desc(colNames ...string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Desc(colNames...) -} - -// Asc will generate "ORDER BY column1,column2 Asc" -// This method can chainable use. -// -// engine.Desc("name").Asc("age").Find(&users) -// // SELECT * FROM user ORDER BY name DESC, age ASC -// -func (engine *Engine) Asc(colNames ...string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Asc(colNames...) -} - -// OrderBy will generate "ORDER BY order" -func (engine *Engine) OrderBy(order string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.OrderBy(order) -} - -// Prepare enables prepare statement -func (engine *Engine) Prepare() *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Prepare() -} - -// Join the join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN -func (engine *Engine) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Join(joinOperator, tablename, condition, args...) -} - -// GroupBy generate group by statement -func (engine *Engine) GroupBy(keys string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.GroupBy(keys) -} - -// Having generate having statement -func (engine *Engine) Having(conditions string) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Having(conditions) -} - -// UnMapType removes the datbase mapper of a type -func (engine *Engine) UnMapType(t reflect.Type) { - engine.mutex.Lock() - defer engine.mutex.Unlock() - delete(engine.Tables, t) -} - -func (engine *Engine) autoMapType(v reflect.Value) (*core.Table, error) { - t := v.Type() - engine.mutex.Lock() - defer engine.mutex.Unlock() - table, ok := engine.Tables[t] - if !ok { - var err error - table, err = engine.mapType(v) - if err != nil { - return nil, err - } - - engine.Tables[t] = table - if engine.Cacher != nil { - if v.CanAddr() { - engine.GobRegister(v.Addr().Interface()) - } else { - engine.GobRegister(v.Interface()) - } - } - } - return table, nil -} - -// GobRegister register one struct to gob for cache use -func (engine *Engine) GobRegister(v interface{}) *Engine { - gob.Register(v) - return engine -} - -// Table table struct -type Table struct { - *core.Table - Name string -} - -// IsValid if table is valid -func (t *Table) IsValid() bool { - return t.Table != nil && len(t.Name) > 0 -} - -// TableInfo get table info according to bean's content -func (engine *Engine) TableInfo(bean interface{}) *Table { - v := rValue(bean) - tb, err := engine.autoMapType(v) - if err != nil { - engine.logger.Error(err) - } - return &Table{tb, engine.TableName(bean)} -} - -func addIndex(indexName string, table *core.Table, col *core.Column, indexType int) { - if index, ok := table.Indexes[indexName]; ok { - index.AddColumn(col.Name) - col.Indexes[index.Name] = indexType - } else { - index := core.NewIndex(indexName, indexType) - index.AddColumn(col.Name) - table.AddIndex(index) - col.Indexes[index.Name] = indexType - } -} - -// TableName table name interface to define customerize table name -type TableName interface { - TableName() string -} - -var ( - tpTableName = reflect.TypeOf((*TableName)(nil)).Elem() -) - -func (engine *Engine) mapType(v reflect.Value) (*core.Table, error) { - t := v.Type() - table := core.NewEmptyTable() - table.Type = t - table.Name = engine.tbNameForMap(v) - - var idFieldColName string - var hasCacheTag, hasNoCacheTag bool - - for i := 0; i < t.NumField(); i++ { - tag := t.Field(i).Tag - - ormTagStr := tag.Get(engine.TagIdentifier) - var col *core.Column - fieldValue := v.Field(i) - fieldType := fieldValue.Type() - - if ormTagStr != "" { - col = &core.Column{ - FieldName: t.Field(i).Name, - Nullable: true, - IsPrimaryKey: false, - IsAutoIncrement: false, - MapType: core.TWOSIDES, - Indexes: make(map[string]int), - DefaultIsEmpty: true, - } - tags := splitTag(ormTagStr) - - if len(tags) > 0 { - if tags[0] == "-" { - continue - } - - var ctx = tagContext{ - table: table, - col: col, - fieldValue: fieldValue, - indexNames: make(map[string]int), - engine: engine, - } - - if strings.HasPrefix(strings.ToUpper(tags[0]), "EXTENDS") { - pStart := strings.Index(tags[0], "(") - if pStart > -1 && strings.HasSuffix(tags[0], ")") { - var tagPrefix = strings.TrimFunc(tags[0][pStart+1:len(tags[0])-1], func(r rune) bool { - return r == '\'' || r == '"' - }) - - ctx.params = []string{tagPrefix} - } - - if err := ExtendsTagHandler(&ctx); err != nil { - return nil, err - } - continue - } - - for j, key := range tags { - if ctx.ignoreNext { - ctx.ignoreNext = false - continue - } - - k := strings.ToUpper(key) - ctx.tagName = k - ctx.params = []string{} - - pStart := strings.Index(k, "(") - if pStart == 0 { - return nil, errors.New("( could not be the first charactor") - } - if pStart > -1 { - if !strings.HasSuffix(k, ")") { - return nil, fmt.Errorf("field %s tag %s cannot match ) charactor", col.FieldName, key) - } - - ctx.tagName = k[:pStart] - ctx.params = strings.Split(key[pStart+1:len(k)-1], ",") - } - - if j > 0 { - ctx.preTag = strings.ToUpper(tags[j-1]) - } - if j < len(tags)-1 { - ctx.nextTag = tags[j+1] - } else { - ctx.nextTag = "" - } - - if h, ok := engine.tagHandlers[ctx.tagName]; ok { - if err := h(&ctx); err != nil { - return nil, err - } - } else { - if strings.HasPrefix(key, "'") && strings.HasSuffix(key, "'") { - col.Name = key[1 : len(key)-1] - } else { - col.Name = key - } - } - - if ctx.hasCacheTag { - hasCacheTag = true - } - if ctx.hasNoCacheTag { - hasNoCacheTag = true - } - } - - if col.SQLType.Name == "" { - col.SQLType = core.Type2SQLType(fieldType) - } - engine.dialect.SqlType(col) - if col.Length == 0 { - col.Length = col.SQLType.DefaultLength - } - if col.Length2 == 0 { - col.Length2 = col.SQLType.DefaultLength2 - } - if col.Name == "" { - col.Name = engine.ColumnMapper.Obj2Table(t.Field(i).Name) - } - - if ctx.isUnique { - ctx.indexNames[col.Name] = core.UniqueType - } else if ctx.isIndex { - ctx.indexNames[col.Name] = core.IndexType - } - - for indexName, indexType := range ctx.indexNames { - addIndex(indexName, table, col, indexType) - } - } - } else { - var sqlType core.SQLType - if fieldValue.CanAddr() { - if _, ok := fieldValue.Addr().Interface().(core.Conversion); ok { - sqlType = core.SQLType{Name: core.Text} - } - } - if _, ok := fieldValue.Interface().(core.Conversion); ok { - sqlType = core.SQLType{Name: core.Text} - } else { - sqlType = core.Type2SQLType(fieldType) - } - col = core.NewColumn(engine.ColumnMapper.Obj2Table(t.Field(i).Name), - t.Field(i).Name, sqlType, sqlType.DefaultLength, - sqlType.DefaultLength2, true) - - if fieldType.Kind() == reflect.Int64 && (strings.ToUpper(col.FieldName) == "ID" || strings.HasSuffix(strings.ToUpper(col.FieldName), ".ID")) { - idFieldColName = col.Name - } - } - if col.IsAutoIncrement { - col.Nullable = false - } - - table.AddColumn(col) - - } // end for - - if idFieldColName != "" && len(table.PrimaryKeys) == 0 { - col := table.GetColumn(idFieldColName) - col.IsPrimaryKey = true - col.IsAutoIncrement = true - col.Nullable = false - table.PrimaryKeys = append(table.PrimaryKeys, col.Name) - table.AutoIncrement = col.Name - } - - if hasCacheTag { - if engine.Cacher != nil { // !nash! use engine's cacher if provided - engine.logger.Info("enable cache on table:", table.Name) - engine.setCacher(table.Name, engine.Cacher) - } else { - engine.logger.Info("enable LRU cache on table:", table.Name) - engine.setCacher(table.Name, NewLRUCacher2(NewMemoryStore(), time.Hour, 10000)) - } - } - if hasNoCacheTag { - engine.logger.Info("disable cache on table:", table.Name) - engine.setCacher(table.Name, nil) - } - - return table, nil -} - -// IsTableEmpty if a table has any reocrd -func (engine *Engine) IsTableEmpty(bean interface{}) (bool, error) { - session := engine.NewSession() - defer session.Close() - return session.IsTableEmpty(bean) -} - -// IsTableExist if a table is exist -func (engine *Engine) IsTableExist(beanOrTableName interface{}) (bool, error) { - session := engine.NewSession() - defer session.Close() - return session.IsTableExist(beanOrTableName) -} - -// IdOf get id from one struct -// -// Deprecated: use IDOf instead. -func (engine *Engine) IdOf(bean interface{}) core.PK { - return engine.IDOf(bean) -} - -// IDOf get id from one struct -func (engine *Engine) IDOf(bean interface{}) core.PK { - return engine.IdOfV(reflect.ValueOf(bean)) -} - -// IdOfV get id from one value of struct -// -// Deprecated: use IDOfV instead. -func (engine *Engine) IdOfV(rv reflect.Value) core.PK { - return engine.IDOfV(rv) -} - -// IDOfV get id from one value of struct -func (engine *Engine) IDOfV(rv reflect.Value) core.PK { - pk, err := engine.idOfV(rv) - if err != nil { - engine.logger.Error(err) - return nil - } - return pk -} - -func (engine *Engine) idOfV(rv reflect.Value) (core.PK, error) { - v := reflect.Indirect(rv) - table, err := engine.autoMapType(v) - if err != nil { - return nil, err - } - - pk := make([]interface{}, len(table.PrimaryKeys)) - for i, col := range table.PKColumns() { - var err error - - fieldName := col.FieldName - for { - parts := strings.SplitN(fieldName, ".", 2) - if len(parts) == 1 { - break - } - - v = v.FieldByName(parts[0]) - if v.Kind() == reflect.Ptr { - v = v.Elem() - } - if v.Kind() != reflect.Struct { - return nil, ErrUnSupportedType - } - fieldName = parts[1] - } - - pkField := v.FieldByName(fieldName) - switch pkField.Kind() { - case reflect.String: - pk[i], err = engine.idTypeAssertion(col, pkField.String()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - pk[i], err = engine.idTypeAssertion(col, strconv.FormatInt(pkField.Int(), 10)) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - // id of uint will be converted to int64 - pk[i], err = engine.idTypeAssertion(col, strconv.FormatUint(pkField.Uint(), 10)) - } - - if err != nil { - return nil, err - } - } - return core.PK(pk), nil -} - -func (engine *Engine) idTypeAssertion(col *core.Column, sid string) (interface{}, error) { - if col.SQLType.IsNumeric() { - n, err := strconv.ParseInt(sid, 10, 64) - if err != nil { - return nil, err - } - return n, nil - } else if col.SQLType.IsText() { - return sid, nil - } else { - return nil, errors.New("not supported") - } -} - -// CreateIndexes create indexes -func (engine *Engine) CreateIndexes(bean interface{}) error { - session := engine.NewSession() - defer session.Close() - return session.CreateIndexes(bean) -} - -// CreateUniques create uniques -func (engine *Engine) CreateUniques(bean interface{}) error { - session := engine.NewSession() - defer session.Close() - return session.CreateUniques(bean) -} - -// ClearCacheBean if enabled cache, clear the cache bean -func (engine *Engine) ClearCacheBean(bean interface{}, id string) error { - tableName := engine.TableName(bean) - cacher := engine.getCacher(tableName) - if cacher != nil { - cacher.ClearIds(tableName) - cacher.DelBean(tableName, id) - } - return nil -} - -// ClearCache if enabled cache, clear some tables' cache -func (engine *Engine) ClearCache(beans ...interface{}) error { - for _, bean := range beans { - tableName := engine.TableName(bean) - cacher := engine.getCacher(tableName) - if cacher != nil { - cacher.ClearIds(tableName) - cacher.ClearBeans(tableName) - } - } - return nil -} - -// Sync the new struct changes to database, this method will automatically add -// table, column, index, unique. but will not delete or change anything. -// If you change some field, you should change the database manually. -func (engine *Engine) Sync(beans ...interface{}) error { - session := engine.NewSession() - defer session.Close() - - for _, bean := range beans { - v := rValue(bean) - tableNameNoSchema := engine.TableName(bean) - table, err := engine.autoMapType(v) - if err != nil { - return err - } - - isExist, err := session.Table(bean).isTableExist(tableNameNoSchema) - if err != nil { - return err - } - if !isExist { - err = session.createTable(bean) - if err != nil { - return err - } - } - /*isEmpty, err := engine.IsEmptyTable(bean) - if err != nil { - return err - }*/ - var isEmpty bool - if isEmpty { - err = session.dropTable(bean) - if err != nil { - return err - } - err = session.createTable(bean) - if err != nil { - return err - } - } else { - for _, col := range table.Columns() { - isExist, err := engine.dialect.IsColumnExist(tableNameNoSchema, col.Name) - if err != nil { - return err - } - if !isExist { - if err := session.statement.setRefBean(bean); err != nil { - return err - } - err = session.addColumn(col.Name) - if err != nil { - return err - } - } - } - - for name, index := range table.Indexes { - if err := session.statement.setRefBean(bean); err != nil { - return err - } - if index.Type == core.UniqueType { - isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, true) - if err != nil { - return err - } - if !isExist { - if err := session.statement.setRefBean(bean); err != nil { - return err - } - - err = session.addUnique(tableNameNoSchema, name) - if err != nil { - return err - } - } - } else if index.Type == core.IndexType { - isExist, err := session.isIndexExist2(tableNameNoSchema, index.Cols, false) - if err != nil { - return err - } - if !isExist { - if err := session.statement.setRefBean(bean); err != nil { - return err - } - - err = session.addIndex(tableNameNoSchema, name) - if err != nil { - return err - } - } - } else { - return errors.New("unknow index type") - } - } - } - } - return nil -} - -// Sync2 synchronize structs to database tables -func (engine *Engine) Sync2(beans ...interface{}) error { - s := engine.NewSession() - defer s.Close() - return s.Sync2(beans...) -} - -// CreateTables create tabls according bean -func (engine *Engine) CreateTables(beans ...interface{}) error { - session := engine.NewSession() - defer session.Close() - - err := session.Begin() - if err != nil { - return err - } - - for _, bean := range beans { - err = session.createTable(bean) - if err != nil { - session.Rollback() - return err - } - } - return session.Commit() -} - -// DropTables drop specify tables -func (engine *Engine) DropTables(beans ...interface{}) error { - session := engine.NewSession() - defer session.Close() - - err := session.Begin() - if err != nil { - return err - } - - for _, bean := range beans { - err = session.dropTable(bean) - if err != nil { - session.Rollback() - return err - } - } - return session.Commit() -} - -// DropIndexes drop indexes of a table -func (engine *Engine) DropIndexes(bean interface{}) error { - session := engine.NewSession() - defer session.Close() - return session.DropIndexes(bean) -} - -// Exec raw sql -func (engine *Engine) Exec(sqlOrArgs ...interface{}) (sql.Result, error) { - session := engine.NewSession() - defer session.Close() - return session.Exec(sqlOrArgs...) -} - -// Query a raw sql and return records as []map[string][]byte -func (engine *Engine) Query(sqlOrArgs ...interface{}) (resultsSlice []map[string][]byte, err error) { - session := engine.NewSession() - defer session.Close() - return session.Query(sqlOrArgs...) -} - -// QueryString runs a raw sql and return records as []map[string]string -func (engine *Engine) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) { - session := engine.NewSession() - defer session.Close() - return session.QueryString(sqlOrArgs...) -} - -// QueryInterface runs a raw sql and return records as []map[string]interface{} -func (engine *Engine) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) { - session := engine.NewSession() - defer session.Close() - return session.QueryInterface(sqlOrArgs...) -} - -// Insert one or more records -func (engine *Engine) Insert(beans ...interface{}) (int64, error) { - session := engine.NewSession() - defer session.Close() - return session.Insert(beans...) -} - -// InsertOne insert only one record -func (engine *Engine) InsertOne(bean interface{}) (int64, error) { - session := engine.NewSession() - defer session.Close() - return session.InsertOne(bean) -} - -// Update records, bean's non-empty fields are updated contents, -// condiBean' non-empty filds are conditions -// CAUTION: -// 1.bool will defaultly be updated content nor conditions -// You should call UseBool if you have bool to use. -// 2.float32 & float64 may be not inexact as conditions -func (engine *Engine) Update(bean interface{}, condiBeans ...interface{}) (int64, error) { - session := engine.NewSession() - defer session.Close() - return session.Update(bean, condiBeans...) -} - -// Delete records, bean's non-empty fields are conditions -func (engine *Engine) Delete(bean interface{}) (int64, error) { - session := engine.NewSession() - defer session.Close() - return session.Delete(bean) -} - -// Get retrieve one record from table, bean's non-empty fields -// are conditions -func (engine *Engine) Get(bean interface{}) (bool, error) { - session := engine.NewSession() - defer session.Close() - return session.Get(bean) -} - -// Exist returns true if the record exist otherwise return false -func (engine *Engine) Exist(bean ...interface{}) (bool, error) { - session := engine.NewSession() - defer session.Close() - return session.Exist(bean...) -} - -// Find retrieve records from table, condiBeans's non-empty fields -// are conditions. beans could be []Struct, []*Struct, map[int64]Struct -// map[int64]*Struct -func (engine *Engine) Find(beans interface{}, condiBeans ...interface{}) error { - session := engine.NewSession() - defer session.Close() - return session.Find(beans, condiBeans...) -} - -// FindAndCount find the results and also return the counts -func (engine *Engine) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) { - session := engine.NewSession() - defer session.Close() - return session.FindAndCount(rowsSlicePtr, condiBean...) -} - -// Iterate record by record handle records from table, bean's non-empty fields -// are conditions. -func (engine *Engine) Iterate(bean interface{}, fun IterFunc) error { - session := engine.NewSession() - defer session.Close() - return session.Iterate(bean, fun) -} - -// Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields -// are conditions. -func (engine *Engine) Rows(bean interface{}) (*Rows, error) { - session := engine.NewSession() - return session.Rows(bean) -} - -// Count counts the records. bean's non-empty fields are conditions. -func (engine *Engine) Count(bean ...interface{}) (int64, error) { - session := engine.NewSession() - defer session.Close() - return session.Count(bean...) -} - -// Sum sum the records by some column. bean's non-empty fields are conditions. -func (engine *Engine) Sum(bean interface{}, colName string) (float64, error) { - session := engine.NewSession() - defer session.Close() - return session.Sum(bean, colName) -} - -// SumInt sum the records by some column. bean's non-empty fields are conditions. -func (engine *Engine) SumInt(bean interface{}, colName string) (int64, error) { - session := engine.NewSession() - defer session.Close() - return session.SumInt(bean, colName) -} - -// Sums sum the records by some columns. bean's non-empty fields are conditions. -func (engine *Engine) Sums(bean interface{}, colNames ...string) ([]float64, error) { - session := engine.NewSession() - defer session.Close() - return session.Sums(bean, colNames...) -} - -// SumsInt like Sums but return slice of int64 instead of float64. -func (engine *Engine) SumsInt(bean interface{}, colNames ...string) ([]int64, error) { - session := engine.NewSession() - defer session.Close() - return session.SumsInt(bean, colNames...) -} - -// ImportFile SQL DDL file -func (engine *Engine) ImportFile(ddlPath string) ([]sql.Result, error) { - file, err := os.Open(ddlPath) - if err != nil { - return nil, err - } - defer file.Close() - return engine.Import(file) -} - -// Import SQL DDL from io.Reader -func (engine *Engine) Import(r io.Reader) ([]sql.Result, error) { - var results []sql.Result - var lastError error - scanner := bufio.NewScanner(r) - - semiColSpliter := func(data []byte, atEOF bool) (advance int, token []byte, err error) { - if atEOF && len(data) == 0 { - return 0, nil, nil - } - if i := bytes.IndexByte(data, ';'); i >= 0 { - return i + 1, data[0:i], nil - } - // If we're at EOF, we have a final, non-terminated line. Return it. - if atEOF { - return len(data), data, nil - } - // Request more data. - return 0, nil, nil - } - - scanner.Split(semiColSpliter) - - for scanner.Scan() { - query := strings.Trim(scanner.Text(), " \t\n\r") - if len(query) > 0 { - engine.logSQL(query) - result, err := engine.DB().Exec(query) - results = append(results, result) - if err != nil { - return nil, err - } - } - } - - return results, lastError -} - -// nowTime return current time -func (engine *Engine) nowTime(col *core.Column) (interface{}, time.Time) { - t := time.Now() - var tz = engine.DatabaseTZ - if !col.DisableTimeZone && col.TimeZone != nil { - tz = col.TimeZone - } - return engine.formatTime(col.SQLType.Name, t.In(tz)), t.In(engine.TZLocation) -} - -func (engine *Engine) formatColTime(col *core.Column, t time.Time) (v interface{}) { - if t.IsZero() { - if col.Nullable { - return nil - } - return "" - } - - if col.TimeZone != nil { - return engine.formatTime(col.SQLType.Name, t.In(col.TimeZone)) - } - return engine.formatTime(col.SQLType.Name, t.In(engine.DatabaseTZ)) -} - -// formatTime format time as column type -func (engine *Engine) formatTime(sqlTypeName string, t time.Time) (v interface{}) { - switch sqlTypeName { - case core.Time: - s := t.Format("2006-01-02 15:04:05") // time.RFC3339 - v = s[11:19] - case core.Date: - v = t.Format("2006-01-02") - case core.DateTime, core.TimeStamp: - v = t.Format("2006-01-02 15:04:05") - case core.TimeStampz: - if engine.dialect.DBType() == core.MSSQL { - v = t.Format("2006-01-02T15:04:05.9999999Z07:00") - } else { - v = t.Format(time.RFC3339Nano) - } - case core.BigInt, core.Int: - v = t.Unix() - default: - v = t - } - return -} - -// GetColumnMapper returns the column name mapper -func (engine *Engine) GetColumnMapper() core.IMapper { - return engine.ColumnMapper -} - -// GetTableMapper returns the table name mapper -func (engine *Engine) GetTableMapper() core.IMapper { - return engine.TableMapper -} - -// GetTZLocation returns time zone of the application -func (engine *Engine) GetTZLocation() *time.Location { - return engine.TZLocation -} - -// SetTZLocation sets time zone of the application -func (engine *Engine) SetTZLocation(tz *time.Location) { - engine.TZLocation = tz -} - -// GetTZDatabase returns time zone of the database -func (engine *Engine) GetTZDatabase() *time.Location { - return engine.DatabaseTZ -} - -// SetTZDatabase sets time zone of the database -func (engine *Engine) SetTZDatabase(tz *time.Location) { - engine.DatabaseTZ = tz -} - -// SetSchema sets the schema of database -func (engine *Engine) SetSchema(schema string) { - engine.dialect.URI().Schema = schema -} - -// Unscoped always disable struct tag "deleted" -func (engine *Engine) Unscoped() *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Unscoped() -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_cond.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_cond.go deleted file mode 100644 index 702ac8043..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_cond.go +++ /dev/null @@ -1,232 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql/driver" - "fmt" - "reflect" - "strings" - "time" - - "xorm.io/builder" - "xorm.io/core" -) - -func (engine *Engine) buildConds(table *core.Table, bean interface{}, - includeVersion bool, includeUpdated bool, includeNil bool, - includeAutoIncr bool, allUseBool bool, useAllCols bool, unscoped bool, - mustColumnMap map[string]bool, tableName, aliasName string, addedTableName bool) (builder.Cond, error) { - var conds []builder.Cond - for _, col := range table.Columns() { - if !includeVersion && col.IsVersion { - continue - } - if !includeUpdated && col.IsUpdated { - continue - } - if !includeAutoIncr && col.IsAutoIncrement { - continue - } - - if engine.dialect.DBType() == core.MSSQL && (col.SQLType.Name == core.Text || col.SQLType.IsBlob() || col.SQLType.Name == core.TimeStampz) { - continue - } - if col.SQLType.IsJson() { - continue - } - - var colName string - if addedTableName { - var nm = tableName - if len(aliasName) > 0 { - nm = aliasName - } - colName = engine.Quote(nm) + "." + engine.Quote(col.Name) - } else { - colName = engine.Quote(col.Name) - } - - fieldValuePtr, err := col.ValueOf(bean) - if err != nil { - if !strings.Contains(err.Error(), "is not valid") { - engine.logger.Warn(err) - } - continue - } - - if col.IsDeleted && !unscoped { // tag "deleted" is enabled - conds = append(conds, engine.CondDeleted(colName)) - } - - fieldValue := *fieldValuePtr - if fieldValue.Interface() == nil { - continue - } - - fieldType := reflect.TypeOf(fieldValue.Interface()) - requiredField := useAllCols - - if b, ok := getFlagForColumn(mustColumnMap, col); ok { - if b { - requiredField = true - } else { - continue - } - } - - if fieldType.Kind() == reflect.Ptr { - if fieldValue.IsNil() { - if includeNil { - conds = append(conds, builder.Eq{colName: nil}) - } - continue - } else if !fieldValue.IsValid() { - continue - } else { - // dereference ptr type to instance type - fieldValue = fieldValue.Elem() - fieldType = reflect.TypeOf(fieldValue.Interface()) - requiredField = true - } - } - - var val interface{} - switch fieldType.Kind() { - case reflect.Bool: - if allUseBool || requiredField { - val = fieldValue.Interface() - } else { - // if a bool in a struct, it will not be as a condition because it default is false, - // please use Where() instead - continue - } - case reflect.String: - if !requiredField && fieldValue.String() == "" { - continue - } - // for MyString, should convert to string or panic - if fieldType.String() != reflect.String.String() { - val = fieldValue.String() - } else { - val = fieldValue.Interface() - } - case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64: - if !requiredField && fieldValue.Int() == 0 { - continue - } - val = fieldValue.Interface() - case reflect.Float32, reflect.Float64: - if !requiredField && fieldValue.Float() == 0.0 { - continue - } - val = fieldValue.Interface() - case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64: - if !requiredField && fieldValue.Uint() == 0 { - continue - } - t := int64(fieldValue.Uint()) - val = reflect.ValueOf(&t).Interface() - case reflect.Struct: - if fieldType.ConvertibleTo(core.TimeType) { - t := fieldValue.Convert(core.TimeType).Interface().(time.Time) - if !requiredField && (t.IsZero() || !fieldValue.IsValid()) { - continue - } - val = engine.formatColTime(col, t) - } else if _, ok := reflect.New(fieldType).Interface().(core.Conversion); ok { - continue - } else if valNul, ok := fieldValue.Interface().(driver.Valuer); ok { - val, _ = valNul.Value() - if val == nil { - continue - } - } else { - if col.SQLType.IsJson() { - if col.SQLType.IsText() { - bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - engine.logger.Error(err) - continue - } - val = string(bytes) - } else if col.SQLType.IsBlob() { - var bytes []byte - var err error - bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - engine.logger.Error(err) - continue - } - val = bytes - } - } else { - engine.autoMapType(fieldValue) - if table, ok := engine.Tables[fieldValue.Type()]; ok { - if len(table.PrimaryKeys) == 1 { - pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName) - // fix non-int pk issues - //if pkField.Int() != 0 { - if pkField.IsValid() && !isZero(pkField.Interface()) { - val = pkField.Interface() - } else { - continue - } - } else { - //TODO: how to handler? - return nil, fmt.Errorf("not supported %v as %v", fieldValue.Interface(), table.PrimaryKeys) - } - } else { - val = fieldValue.Interface() - } - } - } - case reflect.Array: - continue - case reflect.Slice, reflect.Map: - if fieldValue == reflect.Zero(fieldType) { - continue - } - if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 { - continue - } - - if col.SQLType.IsText() { - bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - engine.logger.Error(err) - continue - } - val = string(bytes) - } else if col.SQLType.IsBlob() { - var bytes []byte - var err error - if (fieldType.Kind() == reflect.Array || fieldType.Kind() == reflect.Slice) && - fieldType.Elem().Kind() == reflect.Uint8 { - if fieldValue.Len() > 0 { - val = fieldValue.Bytes() - } else { - continue - } - } else { - bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - engine.logger.Error(err) - continue - } - val = bytes - } - } else { - continue - } - default: - val = fieldValue.Interface() - } - - conds = append(conds, builder.Eq{colName: val}) - } - - return builder.And(conds...), nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_context.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_context.go deleted file mode 100644 index c6cbb76c1..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_context.go +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright 2019 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.8 - -package xorm - -import "context" - -// Context creates a session with the context -func (engine *Engine) Context(ctx context.Context) *Session { - session := engine.NewSession() - session.isAutoClose = true - return session.Context(ctx) -} - -// SetDefaultContext set the default context -func (engine *Engine) SetDefaultContext(ctx context.Context) { - engine.defaultContext = ctx -} - -// PingContext tests if database is alive -func (engine *Engine) PingContext(ctx context.Context) error { - session := engine.NewSession() - defer session.Close() - return session.PingContext(ctx) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_group.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_group.go deleted file mode 100644 index 42d49eca9..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_group.go +++ /dev/null @@ -1,219 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "context" - "time" - - "xorm.io/core" -) - -// EngineGroup defines an engine group -type EngineGroup struct { - *Engine - slaves []*Engine - policy GroupPolicy -} - -// NewEngineGroup creates a new engine group -func NewEngineGroup(args1 interface{}, args2 interface{}, policies ...GroupPolicy) (*EngineGroup, error) { - var eg EngineGroup - if len(policies) > 0 { - eg.policy = policies[0] - } else { - eg.policy = RoundRobinPolicy() - } - - driverName, ok1 := args1.(string) - conns, ok2 := args2.([]string) - if ok1 && ok2 { - engines := make([]*Engine, len(conns)) - for i, conn := range conns { - engine, err := NewEngine(driverName, conn) - if err != nil { - return nil, err - } - engine.engineGroup = &eg - engines[i] = engine - } - - eg.Engine = engines[0] - eg.slaves = engines[1:] - return &eg, nil - } - - master, ok3 := args1.(*Engine) - slaves, ok4 := args2.([]*Engine) - if ok3 && ok4 { - master.engineGroup = &eg - for i := 0; i < len(slaves); i++ { - slaves[i].engineGroup = &eg - } - eg.Engine = master - eg.slaves = slaves - return &eg, nil - } - return nil, ErrParamsType -} - -// Close the engine -func (eg *EngineGroup) Close() error { - err := eg.Engine.Close() - if err != nil { - return err - } - - for i := 0; i < len(eg.slaves); i++ { - err := eg.slaves[i].Close() - if err != nil { - return err - } - } - return nil -} - -// Context returned a group session -func (eg *EngineGroup) Context(ctx context.Context) *Session { - sess := eg.NewSession() - sess.isAutoClose = true - return sess.Context(ctx) -} - -// NewSession returned a group session -func (eg *EngineGroup) NewSession() *Session { - sess := eg.Engine.NewSession() - sess.sessionType = groupSession - return sess -} - -// Master returns the master engine -func (eg *EngineGroup) Master() *Engine { - return eg.Engine -} - -// Ping tests if database is alive -func (eg *EngineGroup) Ping() error { - if err := eg.Engine.Ping(); err != nil { - return err - } - - for _, slave := range eg.slaves { - if err := slave.Ping(); err != nil { - return err - } - } - return nil -} - -// SetColumnMapper set the column name mapping rule -func (eg *EngineGroup) SetColumnMapper(mapper core.IMapper) { - eg.Engine.ColumnMapper = mapper - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].ColumnMapper = mapper - } -} - -// SetConnMaxLifetime sets the maximum amount of time a connection may be reused. -func (eg *EngineGroup) SetConnMaxLifetime(d time.Duration) { - eg.Engine.SetConnMaxLifetime(d) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].SetConnMaxLifetime(d) - } -} - -// SetDefaultCacher set the default cacher -func (eg *EngineGroup) SetDefaultCacher(cacher core.Cacher) { - eg.Engine.SetDefaultCacher(cacher) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].SetDefaultCacher(cacher) - } -} - -// SetLogger set the new logger -func (eg *EngineGroup) SetLogger(logger core.ILogger) { - eg.Engine.SetLogger(logger) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].SetLogger(logger) - } -} - -// SetLogLevel sets the logger level -func (eg *EngineGroup) SetLogLevel(level core.LogLevel) { - eg.Engine.SetLogLevel(level) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].SetLogLevel(level) - } -} - -// SetMapper set the name mapping rules -func (eg *EngineGroup) SetMapper(mapper core.IMapper) { - eg.Engine.SetMapper(mapper) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].SetMapper(mapper) - } -} - -// SetMaxIdleConns set the max idle connections on pool, default is 2 -func (eg *EngineGroup) SetMaxIdleConns(conns int) { - eg.Engine.db.SetMaxIdleConns(conns) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].db.SetMaxIdleConns(conns) - } -} - -// SetMaxOpenConns is only available for go 1.2+ -func (eg *EngineGroup) SetMaxOpenConns(conns int) { - eg.Engine.db.SetMaxOpenConns(conns) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].db.SetMaxOpenConns(conns) - } -} - -// SetPolicy set the group policy -func (eg *EngineGroup) SetPolicy(policy GroupPolicy) *EngineGroup { - eg.policy = policy - return eg -} - -// SetTableMapper set the table name mapping rule -func (eg *EngineGroup) SetTableMapper(mapper core.IMapper) { - eg.Engine.TableMapper = mapper - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].TableMapper = mapper - } -} - -// ShowExecTime show SQL statement and execute time or not on logger if log level is great than INFO -func (eg *EngineGroup) ShowExecTime(show ...bool) { - eg.Engine.ShowExecTime(show...) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].ShowExecTime(show...) - } -} - -// ShowSQL show SQL statement or not on logger if log level is great than INFO -func (eg *EngineGroup) ShowSQL(show ...bool) { - eg.Engine.ShowSQL(show...) - for i := 0; i < len(eg.slaves); i++ { - eg.slaves[i].ShowSQL(show...) - } -} - -// Slave returns one of the physical databases which is a slave according the policy -func (eg *EngineGroup) Slave() *Engine { - switch len(eg.slaves) { - case 0: - return eg.Engine - case 1: - return eg.slaves[0] - } - return eg.policy.Slave(eg) -} - -// Slaves returns all the slaves -func (eg *EngineGroup) Slaves() []*Engine { - return eg.slaves -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_group_policy.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_group_policy.go deleted file mode 100644 index 5b56e8995..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_group_policy.go +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "math/rand" - "sync" - "time" -) - -// GroupPolicy is be used by chosing the current slave from slaves -type GroupPolicy interface { - Slave(*EngineGroup) *Engine -} - -// GroupPolicyHandler should be used when a function is a GroupPolicy -type GroupPolicyHandler func(*EngineGroup) *Engine - -// Slave implements the chosen of slaves -func (h GroupPolicyHandler) Slave(eg *EngineGroup) *Engine { - return h(eg) -} - -// RandomPolicy implmentes randomly chose the slave of slaves -func RandomPolicy() GroupPolicyHandler { - var r = rand.New(rand.NewSource(time.Now().UnixNano())) - return func(g *EngineGroup) *Engine { - return g.Slaves()[r.Intn(len(g.Slaves()))] - } -} - -// WeightRandomPolicy implmentes randomly chose the slave of slaves -func WeightRandomPolicy(weights []int) GroupPolicyHandler { - var rands = make([]int, 0, len(weights)) - for i := 0; i < len(weights); i++ { - for n := 0; n < weights[i]; n++ { - rands = append(rands, i) - } - } - var r = rand.New(rand.NewSource(time.Now().UnixNano())) - - return func(g *EngineGroup) *Engine { - var slaves = g.Slaves() - idx := rands[r.Intn(len(rands))] - if idx >= len(slaves) { - idx = len(slaves) - 1 - } - return slaves[idx] - } -} - -func RoundRobinPolicy() GroupPolicyHandler { - var pos = -1 - var lock sync.Mutex - return func(g *EngineGroup) *Engine { - var slaves = g.Slaves() - - lock.Lock() - defer lock.Unlock() - pos++ - if pos >= len(slaves) { - pos = 0 - } - - return slaves[pos] - } -} - -func WeightRoundRobinPolicy(weights []int) GroupPolicyHandler { - var rands = make([]int, 0, len(weights)) - for i := 0; i < len(weights); i++ { - for n := 0; n < weights[i]; n++ { - rands = append(rands, i) - } - } - var pos = -1 - var lock sync.Mutex - - return func(g *EngineGroup) *Engine { - var slaves = g.Slaves() - lock.Lock() - defer lock.Unlock() - pos++ - if pos >= len(rands) { - pos = 0 - } - - idx := rands[pos] - if idx >= len(slaves) { - idx = len(slaves) - 1 - } - return slaves[idx] - } -} - -// LeastConnPolicy implements GroupPolicy, every time will get the least connections slave -func LeastConnPolicy() GroupPolicyHandler { - return func(g *EngineGroup) *Engine { - var slaves = g.Slaves() - connections := 0 - idx := 0 - for i := 0; i < len(slaves); i++ { - openConnections := slaves[i].DB().Stats().OpenConnections - if i == 0 { - connections = openConnections - idx = i - } else if openConnections <= connections { - connections = openConnections - idx = i - } - } - return slaves[idx] - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_table.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_table.go deleted file mode 100644 index eb5aa850a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/engine_table.go +++ /dev/null @@ -1,113 +0,0 @@ -// Copyright 2018 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "reflect" - "strings" - - "xorm.io/core" -) - -// tbNameWithSchema will automatically add schema prefix on table name -func (engine *Engine) tbNameWithSchema(v string) string { - // Add schema name as prefix of table name. - // Only for postgres database. - if engine.dialect.DBType() == core.POSTGRES && - engine.dialect.URI().Schema != "" && - engine.dialect.URI().Schema != postgresPublicSchema && - strings.Index(v, ".") == -1 { - return engine.dialect.URI().Schema + "." + v - } - return v -} - -// TableName returns table name with schema prefix if has -func (engine *Engine) TableName(bean interface{}, includeSchema ...bool) string { - tbName := engine.tbNameNoSchema(bean) - if len(includeSchema) > 0 && includeSchema[0] { - tbName = engine.tbNameWithSchema(tbName) - } - - return tbName -} - -// tbName get some table's table name -func (session *Session) tbNameNoSchema(table *core.Table) string { - if len(session.statement.AltTableName) > 0 { - return session.statement.AltTableName - } - - return table.Name -} - -func (engine *Engine) tbNameForMap(v reflect.Value) string { - if v.Type().Implements(tpTableName) { - return v.Interface().(TableName).TableName() - } - if v.Kind() == reflect.Ptr { - v = v.Elem() - if v.Type().Implements(tpTableName) { - return v.Interface().(TableName).TableName() - } - } - - return engine.TableMapper.Obj2Table(v.Type().Name()) -} - -func (engine *Engine) tbNameNoSchema(tablename interface{}) string { - switch tablename.(type) { - case []string: - t := tablename.([]string) - if len(t) > 1 { - return fmt.Sprintf("%v AS %v", engine.Quote(t[0]), engine.Quote(t[1])) - } else if len(t) == 1 { - return engine.Quote(t[0]) - } - case []interface{}: - t := tablename.([]interface{}) - l := len(t) - var table string - if l > 0 { - f := t[0] - switch f.(type) { - case string: - table = f.(string) - case TableName: - table = f.(TableName).TableName() - default: - v := rValue(f) - t := v.Type() - if t.Kind() == reflect.Struct { - table = engine.tbNameForMap(v) - } else { - table = engine.Quote(fmt.Sprintf("%v", f)) - } - } - } - if l > 1 { - return fmt.Sprintf("%v AS %v", engine.Quote(table), - engine.Quote(fmt.Sprintf("%v", t[1]))) - } else if l == 1 { - return engine.Quote(table) - } - case TableName: - return tablename.(TableName).TableName() - case string: - return tablename.(string) - case reflect.Value: - v := tablename.(reflect.Value) - return engine.tbNameForMap(v) - default: - v := rValue(tablename) - t := v.Type() - if t.Kind() == reflect.Struct { - return engine.tbNameForMap(v) - } - return engine.Quote(fmt.Sprintf("%v", tablename)) - } - return "" -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/error.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/error.go deleted file mode 100644 index a67527acd..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/error.go +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" -) - -var ( - // ErrParamsType params error - ErrParamsType = errors.New("Params type error") - // ErrTableNotFound table not found error - ErrTableNotFound = errors.New("Table not found") - // ErrUnSupportedType unsupported error - ErrUnSupportedType = errors.New("Unsupported type error") - // ErrNotExist record does not exist error - ErrNotExist = errors.New("Record does not exist") - // ErrCacheFailed cache failed error - ErrCacheFailed = errors.New("Cache failed") - // ErrNeedDeletedCond delete needs less one condition error - ErrNeedDeletedCond = errors.New("Delete action needs at least one condition") - // ErrNotImplemented not implemented - ErrNotImplemented = errors.New("Not implemented") - // ErrConditionType condition type unsupported - ErrConditionType = errors.New("Unsupported condition type") - // ErrUnSupportedSQLType parameter of SQL is not supported - ErrUnSupportedSQLType = errors.New("unsupported sql type") -) - -// ErrFieldIsNotExist columns does not exist -type ErrFieldIsNotExist struct { - FieldName string - TableName string -} - -func (e ErrFieldIsNotExist) Error() string { - return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName) -} - -// ErrFieldIsNotValid is not valid -type ErrFieldIsNotValid struct { - FieldName string - TableName string -} - -func (e ErrFieldIsNotValid) Error() string { - return fmt.Sprintf("field %s is not valid on table %s", e.FieldName, e.TableName) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/README.md b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/README.md deleted file mode 100644 index 666c6cf92..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/README.md +++ /dev/null @@ -1,5 +0,0 @@ -# Xorm Examples - -Notice: all the examples will ask you install extra package `github.com/mattn/go-sqlite3`, since it depends on cgo. You have to compile it after you install a c++ compile. Please see [github.com/mattn/go-sqlite3](https://github.com/mattn/go-sqlite3). - -And then, you can run the examples via `go run xxx.go`. Every go file is a standalone example. diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/cache.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/cache.go deleted file mode 100644 index 0c680d23e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/cache.go +++ /dev/null @@ -1,109 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -// User describes a user -type User struct { - Id int64 - Name string -} - -func main() { - f := "cache.db" - os.Remove(f) - - Orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - Orm.ShowSQL(true) - cacher := xorm.NewLRUCacher(xorm.NewMemoryStore(), 1000) - Orm.SetDefaultCacher(cacher) - - err = Orm.CreateTables(&User{}) - if err != nil { - fmt.Println(err) - return - } - - _, err = Orm.Insert(&User{Name: "xlw"}) - if err != nil { - fmt.Println(err) - return - } - - var users []User - err = Orm.Find(&users) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println("users:", users) - - var users2 []User - err = Orm.Find(&users2) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println("users2:", users2) - - var users3 []User - err = Orm.Find(&users3) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println("users3:", users3) - - user4 := new(User) - has, err := Orm.ID(1).Get(user4) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println("user4:", has, user4) - - user4.Name = "xiaolunwen" - _, err = Orm.ID(1).Update(user4) - if err != nil { - fmt.Println(err) - return - } - fmt.Println("user4:", user4) - - user5 := new(User) - has, err = Orm.ID(1).Get(user5) - if err != nil { - fmt.Println(err) - return - } - fmt.Println("user5:", has, user5) - - _, err = Orm.ID(1).Delete(new(User)) - if err != nil { - fmt.Println(err) - return - } - - for { - user6 := new(User) - has, err = Orm.ID(1).Get(user6) - if err != nil { - fmt.Println(err) - return - } - fmt.Println("user6:", has, user6) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/cachegoroutine.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/cachegoroutine.go deleted file mode 100644 index e5b2b9d78..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/cachegoroutine.go +++ /dev/null @@ -1,108 +0,0 @@ -package main - -import ( - "fmt" - "os" - "time" - - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -// User describes a user -type User struct { - Id int64 - Name string -} - -func sqliteEngine() (*xorm.Engine, error) { - os.Remove("./test.db") - return xorm.NewEngine("sqlite3", "./goroutine.db") -} - -func mysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mysql", "root:@/test?charset=utf8") -} - -var u = &User{} - -func test(engine *xorm.Engine) { - err := engine.CreateTables(u) - if err != nil { - fmt.Println(err) - return - } - - size := 500 - queue := make(chan int, size) - - for i := 0; i < size; i++ { - go func(x int) { - //x := i - err := engine.Ping() - if err != nil { - fmt.Println(err) - } else { - for j := 0; j < 10; j++ { - if x+j < 2 { - _, err = engine.Get(u) - } else if x+j < 4 { - users := make([]User, 0) - err = engine.Find(&users) - } else if x+j < 8 { - _, err = engine.Count(u) - } else if x+j < 16 { - _, err = engine.Insert(&User{Name: "xlw"}) - } else if x+j < 32 { - //_, err = engine.ID(1).Delete(u) - _, err = engine.Delete(u) - } - if err != nil { - fmt.Println(err) - queue <- x - return - } - } - fmt.Printf("%v success!\n", x) - } - queue <- x - }(i) - } - - for i := 0; i < size; i++ { - <-queue - } - - //conns := atomic.LoadInt32(&xorm.ConnectionNum) - //fmt.Println("connection number:", conns) - fmt.Println("end") -} - -func main() { - fmt.Println("-----start sqlite go routines-----") - engine, err := sqliteEngine() - if err != nil { - fmt.Println(err) - return - } - engine.ShowSQL(true) - cacher := xorm.NewLRUCacher2(xorm.NewMemoryStore(), time.Hour, 1000) - engine.SetDefaultCacher(cacher) - fmt.Println(engine) - test(engine) - fmt.Println("test end") - engine.Close() - - fmt.Println("-----start mysql go routines-----") - engine, err = mysqlEngine() - engine.ShowSQL(true) - cacher = xorm.NewLRUCacher2(xorm.NewMemoryStore(), time.Hour, 1000) - engine.SetDefaultCacher(cacher) - if err != nil { - fmt.Println(err) - return - } - defer engine.Close() - test(engine) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/conversion.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/conversion.go deleted file mode 100644 index c0646ee1e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/conversion.go +++ /dev/null @@ -1,81 +0,0 @@ -package main - -import ( - "errors" - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -// Status describes a status -type Status struct { - Name string - Color string -} - -// defines some statuses -var ( - Registered = Status{"Registered", "white"} - Approved = Status{"Approved", "green"} - Removed = Status{"Removed", "red"} - Statuses = map[string]Status{ - Registered.Name: Registered, - Approved.Name: Approved, - Removed.Name: Removed, - } -) - -// FromDB implemented xorm.Conversion convent database data to self -func (s *Status) FromDB(bytes []byte) error { - if r, ok := Statuses[string(bytes)]; ok { - *s = r - return nil - } - return errors.New("no this data") -} - -// ToDB implemented xorm.Conversion convent to database data -func (s *Status) ToDB() ([]byte, error) { - return []byte(s.Name), nil -} - -// User describes a user -type User struct { - Id int64 - Name string - Status Status `xorm:"varchar(40)"` -} - -func main() { - f := "conversion.db" - os.Remove(f) - - Orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - Orm.ShowSQL(true) - err = Orm.CreateTables(&User{}) - if err != nil { - fmt.Println(err) - return - } - - _, err = Orm.Insert(&User{1, "xlw", Registered}) - if err != nil { - fmt.Println(err) - return - } - - users := make([]User, 0) - err = Orm.Find(&users) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println(users) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/derive.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/derive.go deleted file mode 100644 index 905615146..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/derive.go +++ /dev/null @@ -1,70 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -// User describes a user -type User struct { - Id int64 - Name string -} - -// LoginInfo describes a login information -type LoginInfo struct { - Id int64 - IP string - UserId int64 -} - -// LoginInfo1 describes a login information -type LoginInfo1 struct { - LoginInfo `xorm:"extends"` - UserName string -} - -func main() { - f := "derive.db" - os.Remove(f) - - orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - defer orm.Close() - orm.ShowSQL(true) - err = orm.CreateTables(&User{}, &LoginInfo{}) - if err != nil { - fmt.Println(err) - return - } - - _, err = orm.Insert(&User{1, "xlw"}, &LoginInfo{1, "127.0.0.1", 1}) - if err != nil { - fmt.Println(err) - return - } - - info := LoginInfo{} - _, err = orm.ID(1).Get(&info) - if err != nil { - fmt.Println(err) - return - } - fmt.Println(info) - - infos := make([]LoginInfo1, 0) - err = orm.Sql(`select *, (select name from user where id = login_info.user_id) as user_name from - login_info limit 10`).Find(&infos) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println(infos) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/find.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/find.go deleted file mode 100644 index ae710b8ec..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/find.go +++ /dev/null @@ -1,51 +0,0 @@ -package main - -import ( - "fmt" - "os" - "time" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -// User describes a user -type User struct { - Id int64 - Name string - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` -} - -func main() { - f := "conversion.db" - os.Remove(f) - - orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - orm.ShowSQL(true) - - err = orm.CreateTables(&User{}) - if err != nil { - fmt.Println(err) - return - } - - _, err = orm.Insert(&User{Id: 1, Name: "xlw"}) - if err != nil { - fmt.Println(err) - return - } - - users := make([]User, 0) - err = orm.Find(&users) - if err != nil { - fmt.Println(err) - return - } - - fmt.Println(users) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/goroutine.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/goroutine.go deleted file mode 100644 index 0596ec23e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/goroutine.go +++ /dev/null @@ -1,108 +0,0 @@ -package main - -import ( - "fmt" - "os" - "runtime" - - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -// User describes a user -type User struct { - Id int64 - Name string -} - -func sqliteEngine() (*xorm.Engine, error) { - os.Remove("./test.db") - return xorm.NewEngine("sqlite3", "./goroutine.db") -} - -func mysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mysql", "root:@/test?charset=utf8") -} - -var u = &User{} - -func test(engine *xorm.Engine) { - err := engine.CreateTables(u) - if err != nil { - fmt.Println(err) - return - } - - size := 100 - queue := make(chan int, size) - - for i := 0; i < size; i++ { - go func(x int) { - //x := i - err := engine.Ping() - if err != nil { - fmt.Println(err) - } else { - /*err = engine.(u) - if err != nil { - fmt.Println("Map user failed") - } else {*/ - for j := 0; j < 10; j++ { - if x+j < 2 { - _, err = engine.Get(u) - } else if x+j < 4 { - users := make([]User, 0) - err = engine.Find(&users) - } else if x+j < 8 { - _, err = engine.Count(u) - } else if x+j < 16 { - _, err = engine.Insert(&User{Name: "xlw"}) - } else if x+j < 32 { - _, err = engine.ID(1).Delete(u) - } - if err != nil { - fmt.Println(err) - queue <- x - return - } - } - fmt.Printf("%v success!\n", x) - //} - } - queue <- x - }(i) - } - - for i := 0; i < size; i++ { - <-queue - } - - //conns := atomic.LoadInt32(&xorm.ConnectionNum) - //fmt.Println("connection number:", conns) - fmt.Println("end") -} - -func main() { - runtime.GOMAXPROCS(2) - fmt.Println("-----start sqlite go routines-----") - engine, err := sqliteEngine() - if err != nil { - fmt.Println(err) - return - } - engine.ShowSQL(true) - fmt.Println(engine) - test(engine) - fmt.Println("test end") - engine.Close() - - fmt.Println("-----start mysql go routines-----") - engine, err = mysqlEngine() - if err != nil { - fmt.Println(err) - return - } - defer engine.Close() - test(engine) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/maxconnect.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/maxconnect.go deleted file mode 100644 index 72d0a5035..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/maxconnect.go +++ /dev/null @@ -1,108 +0,0 @@ -package main - -import ( - "fmt" - "os" - "runtime" - - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -// User describes a user -type User struct { - Id int64 - Name string -} - -func sqliteEngine() (*xorm.Engine, error) { - os.Remove("./test.db") - return xorm.NewEngine("sqlite3", "./goroutine.db") -} - -func mysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mysql", "root:@/test?charset=utf8") -} - -var u = &User{} - -func test(engine *xorm.Engine) { - err := engine.CreateTables(u) - if err != nil { - fmt.Println(err) - return - } - - engine.ShowSQL(true) - engine.SetMaxOpenConns(5) - - size := 1000 - queue := make(chan int, size) - - for i := 0; i < size; i++ { - go func(x int) { - //x := i - err := engine.Ping() - if err != nil { - fmt.Println(err) - } else { - /*err = engine.Map(u) - if err != nil { - fmt.Println("Map user failed") - } else {*/ - for j := 0; j < 10; j++ { - if x+j < 2 { - _, err = engine.Get(u) - } else if x+j < 4 { - users := make([]User, 0) - err = engine.Find(&users) - } else if x+j < 8 { - _, err = engine.Count(u) - } else if x+j < 16 { - _, err = engine.Insert(&User{Name: "xlw"}) - } else if x+j < 32 { - _, err = engine.ID(1).Delete(u) - } - if err != nil { - fmt.Println(err) - queue <- x - return - } - } - fmt.Printf("%v success!\n", x) - //} - } - queue <- x - }(i) - } - - for i := 0; i < size; i++ { - <-queue - } - - fmt.Println("end") -} - -func main() { - runtime.GOMAXPROCS(2) - fmt.Println("create engine") - engine, err := sqliteEngine() - if err != nil { - fmt.Println(err) - return - } - engine.ShowSQL(true) - fmt.Println(engine) - test(engine) - fmt.Println("------------------------") - engine.Close() - - engine, err = mysqlEngine() - if err != nil { - fmt.Println(err) - return - } - defer engine.Close() - test(engine) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/singlemapping.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/singlemapping.go deleted file mode 100644 index 86e5d1d7d..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/singlemapping.go +++ /dev/null @@ -1,57 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -// User describes a user -type User struct { - Id int64 - Name string -} - -// LoginInfo describes a login information -type LoginInfo struct { - Id int64 - IP string - UserId int64 - // timestamp should be updated by database, so only allow get from db - TimeStamp string `xorm:"<-"` - // assume - Nonuse int `xorm:"->"` -} - -func main() { - f := "singleMapping.db" - os.Remove(f) - - orm, err := xorm.NewEngine("sqlite3", f) - if err != nil { - fmt.Println(err) - return - } - orm.ShowSQL(true) - err = orm.CreateTables(&User{}, &LoginInfo{}) - if err != nil { - fmt.Println(err) - return - } - - _, err = orm.Insert(&User{1, "xlw"}, &LoginInfo{1, "127.0.0.1", 1, "", 23}) - if err != nil { - fmt.Println(err) - return - } - - info := LoginInfo{} - _, err = orm.ID(1).Get(&info) - if err != nil { - fmt.Println(err) - return - } - fmt.Println(info) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/sync.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/sync.go deleted file mode 100644 index 134e2a77d..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/sync.go +++ /dev/null @@ -1,106 +0,0 @@ -package main - -import ( - "fmt" - - _ "github.com/go-sql-driver/mysql" - "github.com/go-xorm/xorm" - _ "github.com/lib/pq" - _ "github.com/mattn/go-sqlite3" -) - -// SyncUser2 describes a user -type SyncUser2 struct { - Id int64 - Name string `xorm:"unique"` - Age int `xorm:"index"` - Title string - Address string - Genre string - Area string - Date int -} - -// SyncLoginInfo2 describes a login information -type SyncLoginInfo2 struct { - Id int64 - IP string `xorm:"index"` - UserId int64 - AddedCol int - // timestamp should be updated by database, so only allow get from db - TimeStamp string - // assume - Nonuse int `xorm:"unique"` - Newa string `xorm:"index"` -} - -func sync(engine *xorm.Engine) error { - return engine.Sync(&SyncLoginInfo2{}, &SyncUser2{}) -} - -func sqliteEngine() (*xorm.Engine, error) { - f := "sync.db" - //os.Remove(f) - - return xorm.NewEngine("sqlite3", f) -} - -func mysqlEngine() (*xorm.Engine, error) { - return xorm.NewEngine("mysql", "root:@/test?charset=utf8") -} - -func postgresEngine() (*xorm.Engine, error) { - return xorm.NewEngine("postgres", "dbname=xorm_test sslmode=disable") -} - -type engineFunc func() (*xorm.Engine, error) - -func main() { - //engines := []engineFunc{sqliteEngine, mysqlEngine, postgresEngine} - //engines := []engineFunc{sqliteEngine} - //engines := []engineFunc{mysqlEngine} - engines := []engineFunc{postgresEngine} - for _, enginefunc := range engines { - Orm, err := enginefunc() - fmt.Println("--------", Orm.DriverName(), "----------") - if err != nil { - fmt.Println(err) - return - } - Orm.ShowSQL(true) - err = sync(Orm) - if err != nil { - fmt.Println(err) - } - - _, err = Orm.Where("id > 0").Delete(&SyncUser2{}) - if err != nil { - fmt.Println(err) - } - - user := &SyncUser2{ - Name: "testsdf", - Age: 15, - Title: "newsfds", - Address: "fasfdsafdsaf", - Genre: "fsafd", - Area: "fafdsafd", - Date: 1000, - } - _, err = Orm.Insert(user) - if err != nil { - fmt.Println(err) - return - } - - isexist, err := Orm.IsTableExist("sync_user2") - if err != nil { - fmt.Println(err) - return - } - if !isexist { - fmt.Println("sync_user2 is not exist") - return - } - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/tables.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/tables.go deleted file mode 100644 index 2087186f7..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/examples/tables.go +++ /dev/null @@ -1,34 +0,0 @@ -package main - -import ( - "fmt" - "os" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" -) - -func main() { - if len(os.Args) < 2 { - fmt.Println("need db path") - return - } - - orm, err := xorm.NewEngine("sqlite3", os.Args[1]) - if err != nil { - fmt.Println(err) - return - } - defer orm.Close() - orm.ShowSQL(true) - - tables, err := orm.DBMetas() - if err != nil { - fmt.Println(err) - return - } - - for _, table := range tables { - fmt.Println(table.Name) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/gen_reserved.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/gen_reserved.sh deleted file mode 100644 index 434a1bfcb..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/gen_reserved.sh +++ /dev/null @@ -1,6 +0,0 @@ -#!/bin/bash -if [ -f $1 ];then - cat $1| awk '{printf("\""$1"\":true,\n")}' -else - echo "argument $1 if not a file!" -fi diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/go.mod b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/go.mod deleted file mode 100644 index 1ab39831a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/go.mod +++ /dev/null @@ -1,20 +0,0 @@ -module github.com/go-xorm/xorm - -go 1.11 - -require ( - github.com/cockroachdb/apd v1.1.0 // indirect - github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 - github.com/go-sql-driver/mysql v1.4.1 - github.com/gofrs/uuid v3.2.0+incompatible // indirect - github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 // indirect - github.com/jackc/pgx v3.6.0+incompatible - github.com/lib/pq v1.0.0 - github.com/mattn/go-sqlite3 v1.10.0 - github.com/pkg/errors v0.8.1 // indirect - github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 // indirect - github.com/stretchr/testify v1.4.0 - github.com/ziutek/mymysql v1.5.4 - xorm.io/builder v0.3.6 - xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb -) diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/go.sum b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/go.sum deleted file mode 100644 index cf637a8e0..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/go.sum +++ /dev/null @@ -1,172 +0,0 @@ -cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= -cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= -cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= -github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= -github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= -github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= -github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= -github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= -github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= -github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= -github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= -github.com/cockroachdb/apd v1.1.0 h1:3LFP3629v+1aKXU5Q37mxmRxX/pIu1nijXydLShEq5I= -github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4 h1:YcpmyvADGYw5LqMnHqSkyIELsHCGF6PkrmM31V8rF7o= -github.com/denisenkom/go-mssqldb v0.0.0-20190707035753-2be1aa521ff4/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= -github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= -github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1:+020luEh2TKB4/GOp8oxxtq0Daoen/Cii55CzbTV6DU= -github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= -github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= -github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= -github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= -github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= -github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= -github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a h1:9wScpmSP5A3Bk8V3XHWUcJmYTh+ZnlHVyc+A4oZYS3Y= -github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/gofrs/uuid v3.2.0+incompatible h1:y12jRkkFxsd7GpqdSZ+/KCs/fJbqpEXSGd4+jfEaewE= -github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= -github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= -github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= -github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= -github.com/google/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= -github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= -github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= -github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= -github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= -github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= -github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= -github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= -github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733 h1:vr3AYkKovP8uR8AvSGGUK1IDqRa5lAAvEkZG1LKaCRc= -github.com/jackc/fake v0.0.0-20150926172116-812a484cc733/go.mod h1:WrMFNQdiFJ80sQsxDoMokWK1W5TQtxBFNpzWTD84ibQ= -github.com/jackc/pgx v3.6.0+incompatible h1:bJeo4JdVbDAW8KB2m8XkFeo8CPipREoG37BwEoKGz+Q= -github.com/jackc/pgx v3.6.0+incompatible/go.mod h1:0ZGrqGqkRlliWnWB4zKnWtjbSWbGkVEFm4TeybAXq+I= -github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= -github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= -github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= -github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= -github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= -github.com/lib/pq v1.0.0 h1:X5PMW56eZitiTeO7tKzZxFCSpbFZJtkMMooicw2us9A= -github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= -github.com/mattn/go-sqlite3 v1.10.0 h1:jbhqpg7tQe4SupckyijYiy0mJJ/pRyHvXf7JdWK860o= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= -github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= -github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= -github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= -github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= -github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= -github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= -github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= -github.com/prometheus/client_golang v0.9.3-0.20190127221311-3c4408c8b829/go.mod h1:p2iRAGwDERtqlqzRXnrOVns+ignqQo//hLXqYxZYVNs= -github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/client_model v0.0.0-20190115171406-56726106282f/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= -github.com/prometheus/common v0.2.0/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= -github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= -github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24 h1:pntxY8Ary0t43dCZ5dqY4YTJCObLY1kIXl0uzMv+7DE= -github.com/shopspring/decimal v0.0.0-20180709203117-cd690d0c9e24/go.mod h1:M+9NzErvs504Cn4c5DxATwIqPbtswREoFCre64PpcG4= -github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= -github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/ziutek/mymysql v1.5.4 h1:GB0qdRGsTwQSBVYuVShFBKaXSnSnYYC2d9knnE1LHFs= -github.com/ziutek/mymysql v1.5.4/go.mod h1:LMSpPZ6DbqWFxNCHW77HeMg9I646SAhApZ/wKdgO/C0= -go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= -golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= -golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5 h1:58fnuSXlxZmFdJyvtTFVmVhcMLU6v5fEb/ok4wyqtNU= -golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= -golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= -golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= -golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= -golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= -golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= -golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= -golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20190602015325-4c4f7f33c9ed/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= -golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= -golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= -golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= -golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190606050223-4d9ae51c2468/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= -google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= -google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/appengine v1.6.0 h1:Tfd7cKwKbFRsI8RMAD3oqqw7JPFRrvFlOsfbgVkjOOw= -google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= -google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/genproto v0.0.0-20190404172233-64821d5d2107/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= -google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= -google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= -gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= -gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= -gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -honnef.co/go/tools v0.0.0-20180728063816-88497007e858/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= -xorm.io/builder v0.3.6 h1:ha28mQ2M+TFx96Hxo+iq6tQgnkC9IZkM6D8w9sKHHF8= -xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= -xorm.io/core v0.7.0 h1:hKxuOKWZNeiFQsSuGet/KV8HZ788hclvAl+7azx3tkM= -xorm.io/core v0.7.0/go.mod h1:TuOJjIVa7e3w/rN8tDcAvuLBMtwzdHPbyOzE6Gk1EUI= -xorm.io/core v0.7.1 h1:I6x6Q6dYb67aDEoYFWr2t8UcKIYjJPyCHS+aXuj5V0Y= -xorm.io/core v0.7.1/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb h1:msX3zG3BPl8Ti+LDzP33/9K7BzO/WqFXk610K1kYKfo= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/helpers.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/helpers.go deleted file mode 100644 index a31e922c0..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/helpers.go +++ /dev/null @@ -1,332 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "reflect" - "sort" - "strconv" - "strings" - - "xorm.io/core" -) - -// str2PK convert string value to primary key value according to tp -func str2PKValue(s string, tp reflect.Type) (reflect.Value, error) { - var err error - var result interface{} - var defReturn = reflect.Zero(tp) - - switch tp.Kind() { - case reflect.Int: - result, err = strconv.Atoi(s) - if err != nil { - return defReturn, fmt.Errorf("convert %s as int: %s", s, err.Error()) - } - case reflect.Int8: - x, err := strconv.Atoi(s) - if err != nil { - return defReturn, fmt.Errorf("convert %s as int8: %s", s, err.Error()) - } - result = int8(x) - case reflect.Int16: - x, err := strconv.Atoi(s) - if err != nil { - return defReturn, fmt.Errorf("convert %s as int16: %s", s, err.Error()) - } - result = int16(x) - case reflect.Int32: - x, err := strconv.Atoi(s) - if err != nil { - return defReturn, fmt.Errorf("convert %s as int32: %s", s, err.Error()) - } - result = int32(x) - case reflect.Int64: - result, err = strconv.ParseInt(s, 10, 64) - if err != nil { - return defReturn, fmt.Errorf("convert %s as int64: %s", s, err.Error()) - } - case reflect.Uint: - x, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return defReturn, fmt.Errorf("convert %s as uint: %s", s, err.Error()) - } - result = uint(x) - case reflect.Uint8: - x, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return defReturn, fmt.Errorf("convert %s as uint8: %s", s, err.Error()) - } - result = uint8(x) - case reflect.Uint16: - x, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return defReturn, fmt.Errorf("convert %s as uint16: %s", s, err.Error()) - } - result = uint16(x) - case reflect.Uint32: - x, err := strconv.ParseUint(s, 10, 64) - if err != nil { - return defReturn, fmt.Errorf("convert %s as uint32: %s", s, err.Error()) - } - result = uint32(x) - case reflect.Uint64: - result, err = strconv.ParseUint(s, 10, 64) - if err != nil { - return defReturn, fmt.Errorf("convert %s as uint64: %s", s, err.Error()) - } - case reflect.String: - result = s - default: - return defReturn, errors.New("unsupported convert type") - } - return reflect.ValueOf(result).Convert(tp), nil -} - -func str2PK(s string, tp reflect.Type) (interface{}, error) { - v, err := str2PKValue(s, tp) - if err != nil { - return nil, err - } - return v.Interface(), nil -} - -func splitTag(tag string) (tags []string) { - tag = strings.TrimSpace(tag) - var hasQuote = false - var lastIdx = 0 - for i, t := range tag { - if t == '\'' { - hasQuote = !hasQuote - } else if t == ' ' { - if lastIdx < i && !hasQuote { - tags = append(tags, strings.TrimSpace(tag[lastIdx:i])) - lastIdx = i + 1 - } - } - } - if lastIdx < len(tag) { - tags = append(tags, strings.TrimSpace(tag[lastIdx:])) - } - return -} - -type zeroable interface { - IsZero() bool -} - -func isZero(k interface{}) bool { - switch k.(type) { - case int: - return k.(int) == 0 - case int8: - return k.(int8) == 0 - case int16: - return k.(int16) == 0 - case int32: - return k.(int32) == 0 - case int64: - return k.(int64) == 0 - case uint: - return k.(uint) == 0 - case uint8: - return k.(uint8) == 0 - case uint16: - return k.(uint16) == 0 - case uint32: - return k.(uint32) == 0 - case uint64: - return k.(uint64) == 0 - case float32: - return k.(float32) == 0 - case float64: - return k.(float64) == 0 - case bool: - return k.(bool) == false - case string: - return k.(string) == "" - case zeroable: - return k.(zeroable).IsZero() - } - return false -} - -func isStructZero(v reflect.Value) bool { - if !v.IsValid() { - return true - } - - for i := 0; i < v.NumField(); i++ { - field := v.Field(i) - switch field.Kind() { - case reflect.Ptr: - field = field.Elem() - fallthrough - case reflect.Struct: - if !isStructZero(field) { - return false - } - default: - if field.CanInterface() && !isZero(field.Interface()) { - return false - } - } - } - return true -} - -func isArrayValueZero(v reflect.Value) bool { - if !v.IsValid() || v.Len() == 0 { - return true - } - - for i := 0; i < v.Len(); i++ { - if !isZero(v.Index(i).Interface()) { - return false - } - } - - return true -} - -func int64ToIntValue(id int64, tp reflect.Type) reflect.Value { - var v interface{} - kind := tp.Kind() - - if kind == reflect.Ptr { - kind = tp.Elem().Kind() - } - - switch kind { - case reflect.Int16: - temp := int16(id) - v = &temp - case reflect.Int32: - temp := int32(id) - v = &temp - case reflect.Int: - temp := int(id) - v = &temp - case reflect.Int64: - temp := id - v = &temp - case reflect.Uint16: - temp := uint16(id) - v = &temp - case reflect.Uint32: - temp := uint32(id) - v = &temp - case reflect.Uint64: - temp := uint64(id) - v = &temp - case reflect.Uint: - temp := uint(id) - v = &temp - } - - if tp.Kind() == reflect.Ptr { - return reflect.ValueOf(v).Convert(tp) - } - return reflect.ValueOf(v).Elem().Convert(tp) -} - -func int64ToInt(id int64, tp reflect.Type) interface{} { - return int64ToIntValue(id, tp).Interface() -} - -func isPKZero(pk core.PK) bool { - for _, k := range pk { - if isZero(k) { - return true - } - } - return false -} - -func indexNoCase(s, sep string) int { - return strings.Index(strings.ToLower(s), strings.ToLower(sep)) -} - -func splitNoCase(s, sep string) []string { - idx := indexNoCase(s, sep) - if idx < 0 { - return []string{s} - } - return strings.Split(s, s[idx:idx+len(sep)]) -} - -func splitNNoCase(s, sep string, n int) []string { - idx := indexNoCase(s, sep) - if idx < 0 { - return []string{s} - } - return strings.SplitN(s, s[idx:idx+len(sep)], n) -} - -func makeArray(elem string, count int) []string { - res := make([]string, count) - for i := 0; i < count; i++ { - res[i] = elem - } - return res -} - -func rValue(bean interface{}) reflect.Value { - return reflect.Indirect(reflect.ValueOf(bean)) -} - -func rType(bean interface{}) reflect.Type { - sliceValue := reflect.Indirect(reflect.ValueOf(bean)) - // return reflect.TypeOf(sliceValue.Interface()) - return sliceValue.Type() -} - -func structName(v reflect.Type) string { - for v.Kind() == reflect.Ptr { - v = v.Elem() - } - return v.Name() -} - -func sliceEq(left, right []string) bool { - if len(left) != len(right) { - return false - } - sort.Sort(sort.StringSlice(left)) - sort.Sort(sort.StringSlice(right)) - for i := 0; i < len(left); i++ { - if left[i] != right[i] { - return false - } - } - return true -} - -func indexName(tableName, idxName string) string { - return fmt.Sprintf("IDX_%v_%v", tableName, idxName) -} - -func eraseAny(value string, strToErase ...string) string { - if len(strToErase) == 0 { - return value - } - var replaceSeq []string - for _, s := range strToErase { - replaceSeq = append(replaceSeq, s, "") - } - - replacer := strings.NewReplacer(replaceSeq...) - - return replacer.Replace(value) -} - -func quoteColumns(cols []string, quoteFunc func(string) string, sep string) string { - for i := range cols { - cols[i] = quoteFunc(cols[i]) - } - return strings.Join(cols, sep+" ") -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/helpler_time.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/helpler_time.go deleted file mode 100644 index f4013e27e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/helpler_time.go +++ /dev/null @@ -1,21 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import "time" - -const ( - zeroTime0 = "0000-00-00 00:00:00" - zeroTime1 = "0001-01-01 00:00:00" -) - -func formatTime(t time.Time) string { - return t.Format("2006-01-02 15:04:05") -} - -func isTimeZero(t time.Time) bool { - return t.IsZero() || formatTime(t) == zeroTime0 || - formatTime(t) == zeroTime1 -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/interface.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/interface.go deleted file mode 100644 index a564db126..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/interface.go +++ /dev/null @@ -1,118 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "context" - "database/sql" - "reflect" - "time" - - "xorm.io/core" -) - -// Interface defines the interface which Engine, EngineGroup and Session will implementate. -type Interface interface { - AllCols() *Session - Alias(alias string) *Session - Asc(colNames ...string) *Session - BufferSize(size int) *Session - Cols(columns ...string) *Session - Count(...interface{}) (int64, error) - CreateIndexes(bean interface{}) error - CreateUniques(bean interface{}) error - Decr(column string, arg ...interface{}) *Session - Desc(...string) *Session - Delete(interface{}) (int64, error) - Distinct(columns ...string) *Session - DropIndexes(bean interface{}) error - Exec(sqlOrArgs ...interface{}) (sql.Result, error) - Exist(bean ...interface{}) (bool, error) - Find(interface{}, ...interface{}) error - FindAndCount(interface{}, ...interface{}) (int64, error) - Get(interface{}) (bool, error) - GroupBy(keys string) *Session - ID(interface{}) *Session - In(string, ...interface{}) *Session - Incr(column string, arg ...interface{}) *Session - Insert(...interface{}) (int64, error) - InsertOne(interface{}) (int64, error) - IsTableEmpty(bean interface{}) (bool, error) - IsTableExist(beanOrTableName interface{}) (bool, error) - Iterate(interface{}, IterFunc) error - Limit(int, ...int) *Session - MustCols(columns ...string) *Session - NoAutoCondition(...bool) *Session - NotIn(string, ...interface{}) *Session - Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session - Omit(columns ...string) *Session - OrderBy(order string) *Session - Ping() error - Query(sqlOrArgs ...interface{}) (resultsSlice []map[string][]byte, err error) - QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) - QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) - Rows(bean interface{}) (*Rows, error) - SetExpr(string, interface{}) *Session - SQL(interface{}, ...interface{}) *Session - Sum(bean interface{}, colName string) (float64, error) - SumInt(bean interface{}, colName string) (int64, error) - Sums(bean interface{}, colNames ...string) ([]float64, error) - SumsInt(bean interface{}, colNames ...string) ([]int64, error) - Table(tableNameOrBean interface{}) *Session - Unscoped() *Session - Update(bean interface{}, condiBeans ...interface{}) (int64, error) - UseBool(...string) *Session - Where(interface{}, ...interface{}) *Session -} - -// EngineInterface defines the interface which Engine, EngineGroup will implementate. -type EngineInterface interface { - Interface - - Before(func(interface{})) *Session - Charset(charset string) *Session - ClearCache(...interface{}) error - Context(context.Context) *Session - CreateTables(...interface{}) error - DBMetas() ([]*core.Table, error) - Dialect() core.Dialect - DropTables(...interface{}) error - DumpAllToFile(fp string, tp ...core.DbType) error - GetCacher(string) core.Cacher - GetColumnMapper() core.IMapper - GetDefaultCacher() core.Cacher - GetTableMapper() core.IMapper - GetTZDatabase() *time.Location - GetTZLocation() *time.Location - MapCacher(interface{}, core.Cacher) error - NewSession() *Session - NoAutoTime() *Session - Quote(string) string - SetCacher(string, core.Cacher) - SetConnMaxLifetime(time.Duration) - SetDefaultCacher(core.Cacher) - SetLogger(logger core.ILogger) - SetLogLevel(core.LogLevel) - SetMapper(core.IMapper) - SetMaxOpenConns(int) - SetMaxIdleConns(int) - SetSchema(string) - SetTZDatabase(tz *time.Location) - SetTZLocation(tz *time.Location) - ShowExecTime(...bool) - ShowSQL(show ...bool) - Sync(...interface{}) error - Sync2(...interface{}) error - StoreEngine(storeEngine string) *Session - TableInfo(bean interface{}) *Table - TableName(interface{}, ...bool) string - UnMapType(reflect.Type) -} - -var ( - _ Interface = &Session{} - _ EngineInterface = &Engine{} - _ EngineInterface = &EngineGroup{} -) diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/json.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/json.go deleted file mode 100644 index fdb6ce565..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/json.go +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2019 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import "encoding/json" - -// JSONInterface represents an interface to handle json data -type JSONInterface interface { - Marshal(v interface{}) ([]byte, error) - Unmarshal(data []byte, v interface{}) error -} - -var ( - // DefaultJSONHandler default json handler - DefaultJSONHandler JSONInterface = StdJSON{} -) - -// StdJSON implements JSONInterface via encoding/json -type StdJSON struct{} - -// Marshal implements JSONInterface -func (StdJSON) Marshal(v interface{}) ([]byte, error) { - return json.Marshal(v) -} - -// Unmarshal implements JSONInterface -func (StdJSON) Unmarshal(data []byte, v interface{}) error { - return json.Unmarshal(data, v) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/logger.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/logger.go deleted file mode 100644 index 7b26e77f3..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/logger.go +++ /dev/null @@ -1,187 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "io" - "log" - - "xorm.io/core" -) - -// default log options -const ( - DEFAULT_LOG_PREFIX = "[xorm]" - DEFAULT_LOG_FLAG = log.Ldate | log.Lmicroseconds - DEFAULT_LOG_LEVEL = core.LOG_DEBUG -) - -var _ core.ILogger = DiscardLogger{} - -// DiscardLogger don't log implementation for core.ILogger -type DiscardLogger struct{} - -// Debug empty implementation -func (DiscardLogger) Debug(v ...interface{}) {} - -// Debugf empty implementation -func (DiscardLogger) Debugf(format string, v ...interface{}) {} - -// Error empty implementation -func (DiscardLogger) Error(v ...interface{}) {} - -// Errorf empty implementation -func (DiscardLogger) Errorf(format string, v ...interface{}) {} - -// Info empty implementation -func (DiscardLogger) Info(v ...interface{}) {} - -// Infof empty implementation -func (DiscardLogger) Infof(format string, v ...interface{}) {} - -// Warn empty implementation -func (DiscardLogger) Warn(v ...interface{}) {} - -// Warnf empty implementation -func (DiscardLogger) Warnf(format string, v ...interface{}) {} - -// Level empty implementation -func (DiscardLogger) Level() core.LogLevel { - return core.LOG_UNKNOWN -} - -// SetLevel empty implementation -func (DiscardLogger) SetLevel(l core.LogLevel) {} - -// ShowSQL empty implementation -func (DiscardLogger) ShowSQL(show ...bool) {} - -// IsShowSQL empty implementation -func (DiscardLogger) IsShowSQL() bool { - return false -} - -// SimpleLogger is the default implment of core.ILogger -type SimpleLogger struct { - DEBUG *log.Logger - ERR *log.Logger - INFO *log.Logger - WARN *log.Logger - level core.LogLevel - showSQL bool -} - -var _ core.ILogger = &SimpleLogger{} - -// NewSimpleLogger use a special io.Writer as logger output -func NewSimpleLogger(out io.Writer) *SimpleLogger { - return NewSimpleLogger2(out, DEFAULT_LOG_PREFIX, DEFAULT_LOG_FLAG) -} - -// NewSimpleLogger2 let you customrize your logger prefix and flag -func NewSimpleLogger2(out io.Writer, prefix string, flag int) *SimpleLogger { - return NewSimpleLogger3(out, prefix, flag, DEFAULT_LOG_LEVEL) -} - -// NewSimpleLogger3 let you customrize your logger prefix and flag and logLevel -func NewSimpleLogger3(out io.Writer, prefix string, flag int, l core.LogLevel) *SimpleLogger { - return &SimpleLogger{ - DEBUG: log.New(out, fmt.Sprintf("%s [debug] ", prefix), flag), - ERR: log.New(out, fmt.Sprintf("%s [error] ", prefix), flag), - INFO: log.New(out, fmt.Sprintf("%s [info] ", prefix), flag), - WARN: log.New(out, fmt.Sprintf("%s [warn] ", prefix), flag), - level: l, - } -} - -// Error implement core.ILogger -func (s *SimpleLogger) Error(v ...interface{}) { - if s.level <= core.LOG_ERR { - s.ERR.Output(2, fmt.Sprint(v...)) - } - return -} - -// Errorf implement core.ILogger -func (s *SimpleLogger) Errorf(format string, v ...interface{}) { - if s.level <= core.LOG_ERR { - s.ERR.Output(2, fmt.Sprintf(format, v...)) - } - return -} - -// Debug implement core.ILogger -func (s *SimpleLogger) Debug(v ...interface{}) { - if s.level <= core.LOG_DEBUG { - s.DEBUG.Output(2, fmt.Sprint(v...)) - } - return -} - -// Debugf implement core.ILogger -func (s *SimpleLogger) Debugf(format string, v ...interface{}) { - if s.level <= core.LOG_DEBUG { - s.DEBUG.Output(2, fmt.Sprintf(format, v...)) - } - return -} - -// Info implement core.ILogger -func (s *SimpleLogger) Info(v ...interface{}) { - if s.level <= core.LOG_INFO { - s.INFO.Output(2, fmt.Sprint(v...)) - } - return -} - -// Infof implement core.ILogger -func (s *SimpleLogger) Infof(format string, v ...interface{}) { - if s.level <= core.LOG_INFO { - s.INFO.Output(2, fmt.Sprintf(format, v...)) - } - return -} - -// Warn implement core.ILogger -func (s *SimpleLogger) Warn(v ...interface{}) { - if s.level <= core.LOG_WARNING { - s.WARN.Output(2, fmt.Sprint(v...)) - } - return -} - -// Warnf implement core.ILogger -func (s *SimpleLogger) Warnf(format string, v ...interface{}) { - if s.level <= core.LOG_WARNING { - s.WARN.Output(2, fmt.Sprintf(format, v...)) - } - return -} - -// Level implement core.ILogger -func (s *SimpleLogger) Level() core.LogLevel { - return s.level -} - -// SetLevel implement core.ILogger -func (s *SimpleLogger) SetLevel(l core.LogLevel) { - s.level = l - return -} - -// ShowSQL implement core.ILogger -func (s *SimpleLogger) ShowSQL(show ...bool) { - if len(show) == 0 { - s.showSQL = true - return - } - s.showSQL = show[0] -} - -// IsShowSQL implement core.ILogger -func (s *SimpleLogger) IsShowSQL() bool { - return s.showSQL -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/migrate/migrate.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/migrate/migrate.go deleted file mode 100644 index dc4cd1b53..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/migrate/migrate.go +++ /dev/null @@ -1,217 +0,0 @@ -package migrate - -import ( - "errors" - "fmt" - - "github.com/go-xorm/xorm" -) - -// MigrateFunc is the func signature for migrating. -type MigrateFunc func(*xorm.Engine) error - -// RollbackFunc is the func signature for rollbacking. -type RollbackFunc func(*xorm.Engine) error - -// InitSchemaFunc is the func signature for initializing the schema. -type InitSchemaFunc func(*xorm.Engine) error - -// Options define options for all migrations. -type Options struct { - // TableName is the migration table. - TableName string - // IDColumnName is the name of column where the migration id will be stored. - IDColumnName string -} - -// Migration represents a database migration (a modification to be made on the database). -type Migration struct { - // ID is the migration identifier. Usually a timestamp like "201601021504". - ID string - // Migrate is a function that will br executed while running this migration. - Migrate MigrateFunc - // Rollback will be executed on rollback. Can be nil. - Rollback RollbackFunc -} - -// Migrate represents a collection of all migrations of a database schema. -type Migrate struct { - db *xorm.Engine - options *Options - migrations []*Migration - initSchema InitSchemaFunc -} - -var ( - // DefaultOptions can be used if you don't want to think about options. - DefaultOptions = &Options{ - TableName: "migrations", - IDColumnName: "id", - } - - // ErrRollbackImpossible is returned when trying to rollback a migration - // that has no rollback function. - ErrRollbackImpossible = errors.New("It's impossible to rollback this migration") - - // ErrNoMigrationDefined is returned when no migration is defined. - ErrNoMigrationDefined = errors.New("No migration defined") - - // ErrMissingID is returned when the ID od migration is equal to "" - ErrMissingID = errors.New("Missing ID in migration") - - // ErrNoRunnedMigration is returned when any runned migration was found while - // running RollbackLast - ErrNoRunnedMigration = errors.New("Could not find last runned migration") -) - -// New returns a new Gormigrate. -func New(db *xorm.Engine, options *Options, migrations []*Migration) *Migrate { - return &Migrate{ - db: db, - options: options, - migrations: migrations, - } -} - -// InitSchema sets a function that is run if no migration is found. -// The idea is preventing to run all migrations when a new clean database -// is being migrating. In this function you should create all tables and -// foreign key necessary to your application. -func (m *Migrate) InitSchema(initSchema InitSchemaFunc) { - m.initSchema = initSchema -} - -// Migrate executes all migrations that did not run yet. -func (m *Migrate) Migrate() error { - if err := m.createMigrationTableIfNotExists(); err != nil { - return err - } - - if m.initSchema != nil && m.isFirstRun() { - return m.runInitSchema() - } - - for _, migration := range m.migrations { - if err := m.runMigration(migration); err != nil { - return err - } - } - return nil -} - -// RollbackLast undo the last migration -func (m *Migrate) RollbackLast() error { - if len(m.migrations) == 0 { - return ErrNoMigrationDefined - } - - lastRunnedMigration, err := m.getLastRunnedMigration() - if err != nil { - return err - } - - if err := m.RollbackMigration(lastRunnedMigration); err != nil { - return err - } - return nil -} - -func (m *Migrate) getLastRunnedMigration() (*Migration, error) { - for i := len(m.migrations) - 1; i >= 0; i-- { - migration := m.migrations[i] - run, err := m.migrationDidRun(migration) - if err != nil { - return nil, err - } else if run { - return migration, nil - } - } - return nil, ErrNoRunnedMigration -} - -// RollbackMigration undo a migration. -func (m *Migrate) RollbackMigration(mig *Migration) error { - if mig.Rollback == nil { - return ErrRollbackImpossible - } - - if err := mig.Rollback(m.db); err != nil { - return err - } - - sql := fmt.Sprintf("DELETE FROM %s WHERE %s = ?", m.options.TableName, m.options.IDColumnName) - if _, err := m.db.Exec(sql, mig.ID); err != nil { - return err - } - return nil -} - -func (m *Migrate) runInitSchema() error { - if err := m.initSchema(m.db); err != nil { - return err - } - - for _, migration := range m.migrations { - if err := m.insertMigration(migration.ID); err != nil { - return err - } - } - - return nil -} - -func (m *Migrate) runMigration(migration *Migration) error { - if len(migration.ID) == 0 { - return ErrMissingID - } - - run, err := m.migrationDidRun(migration) - if err != nil { - return err - } - - if !run { - if err := migration.Migrate(m.db); err != nil { - return err - } - - if err := m.insertMigration(migration.ID); err != nil { - return err - } - } - return nil -} - -func (m *Migrate) createMigrationTableIfNotExists() error { - exists, err := m.db.IsTableExist(m.options.TableName) - if err != nil { - return err - } - if exists { - return nil - } - - sql := fmt.Sprintf("CREATE TABLE %s (%s VARCHAR(255) PRIMARY KEY)", m.options.TableName, m.options.IDColumnName) - if _, err := m.db.Exec(sql); err != nil { - return err - } - return nil -} - -func (m *Migrate) migrationDidRun(mig *Migration) (bool, error) { - count, err := m.db.SQL(fmt.Sprintf("SELECT COUNT(*) FROM %s WHERE %s = ?", m.options.TableName, m.options.IDColumnName), mig.ID).Count() - return count > 0, err -} - -func (m *Migrate) isFirstRun() bool { - row := m.db.DB().QueryRow(fmt.Sprintf("SELECT COUNT(*) FROM %s", m.options.TableName)) - var count int - row.Scan(&count) - return count == 0 -} - -func (m *Migrate) insertMigration(id string) error { - sql := fmt.Sprintf("INSERT INTO %s (%s) VALUES (?)", m.options.TableName, m.options.IDColumnName) - _, err := m.db.Exec(sql, id) - return err -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/migrate/migrate_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/migrate/migrate_test.go deleted file mode 100644 index 2452cce28..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/migrate/migrate_test.go +++ /dev/null @@ -1,150 +0,0 @@ -package migrate - -import ( - "fmt" - "log" - "os" - "testing" - - "github.com/go-xorm/xorm" - _ "github.com/mattn/go-sqlite3" - "github.com/stretchr/testify/assert" -) - -type Person struct { - ID int64 - Name string -} - -type Pet struct { - ID int64 - Name string - PersonID int -} - -const ( - dbName = "testdb.sqlite3" -) - -var ( - migrations = []*Migration{ - { - ID: "201608301400", - Migrate: func(tx *xorm.Engine) error { - return tx.Sync2(&Person{}) - }, - Rollback: func(tx *xorm.Engine) error { - return tx.DropTables(&Person{}) - }, - }, - { - ID: "201608301430", - Migrate: func(tx *xorm.Engine) error { - return tx.Sync2(&Pet{}) - }, - Rollback: func(tx *xorm.Engine) error { - return tx.DropTables(&Pet{}) - }, - }, - } -) - -func TestMigration(t *testing.T) { - _ = os.Remove(dbName) - - db, err := xorm.NewEngine("sqlite3", dbName) - if err != nil { - log.Fatal(err) - } - defer db.Close() - - if err = db.DB().Ping(); err != nil { - log.Fatal(err) - } - - m := New(db, DefaultOptions, migrations) - - err = m.Migrate() - assert.NoError(t, err) - exists, _ := db.IsTableExist(&Person{}) - assert.True(t, exists) - exists, _ = db.IsTableExist(&Pet{}) - assert.True(t, exists) - assert.Equal(t, 2, tableCount(db, "migrations")) - - err = m.RollbackLast() - assert.NoError(t, err) - exists, _ = db.IsTableExist(&Person{}) - assert.True(t, exists) - exists, _ = db.IsTableExist(&Pet{}) - assert.False(t, exists) - assert.Equal(t, 1, tableCount(db, "migrations")) - - err = m.RollbackLast() - assert.NoError(t, err) - exists, _ = db.IsTableExist(&Person{}) - assert.False(t, exists) - exists, _ = db.IsTableExist(&Pet{}) - assert.False(t, exists) - assert.Equal(t, 0, tableCount(db, "migrations")) -} - -func TestInitSchema(t *testing.T) { - os.Remove(dbName) - - db, err := xorm.NewEngine("sqlite3", dbName) - if err != nil { - log.Fatal(err) - } - defer db.Close() - if err = db.DB().Ping(); err != nil { - log.Fatal(err) - } - - m := New(db, DefaultOptions, migrations) - m.InitSchema(func(tx *xorm.Engine) error { - if err := tx.Sync2(&Person{}); err != nil { - return err - } - if err := tx.Sync2(&Pet{}); err != nil { - return err - } - return nil - }) - - err = m.Migrate() - assert.NoError(t, err) - exists, _ := db.IsTableExist(&Person{}) - assert.True(t, exists) - exists, _ = db.IsTableExist(&Pet{}) - assert.True(t, exists) - assert.Equal(t, 2, tableCount(db, "migrations")) -} - -func TestMissingID(t *testing.T) { - os.Remove(dbName) - - db, err := xorm.NewEngine("sqlite3", dbName) - assert.NoError(t, err) - if db != nil { - defer db.Close() - } - assert.NoError(t, db.DB().Ping()) - - migrationsMissingID := []*Migration{ - { - Migrate: func(tx *xorm.Engine) error { - return nil - }, - }, - } - - m := New(db, DefaultOptions, migrationsMissingID) - assert.Equal(t, ErrMissingID, m.Migrate()) -} - -func tableCount(db *xorm.Engine, tableName string) (count int) { - row := db.DB().QueryRow(fmt.Sprintf("SELECT COUNT(*) FROM %s", tableName)) - row.Scan(&count) - return -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/pg_reserved.txt b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/pg_reserved.txt deleted file mode 100644 index 720ed377b..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/pg_reserved.txt +++ /dev/null @@ -1,746 +0,0 @@ -A non-reserved non-reserved -ABORT non-reserved -ABS reserved reserved -ABSENT non-reserved non-reserved -ABSOLUTE non-reserved non-reserved non-reserved reserved -ACCESS non-reserved -ACCORDING non-reserved non-reserved -ACTION non-reserved non-reserved non-reserved reserved -ADA non-reserved non-reserved non-reserved -ADD non-reserved non-reserved non-reserved reserved -ADMIN non-reserved non-reserved non-reserved -AFTER non-reserved non-reserved non-reserved -AGGREGATE non-reserved -ALL reserved reserved reserved reserved -ALLOCATE reserved reserved reserved -ALSO non-reserved -ALTER non-reserved reserved reserved reserved -ALWAYS non-reserved non-reserved non-reserved -ANALYSE reserved -ANALYZE reserved -AND reserved reserved reserved reserved -ANY reserved reserved reserved reserved -ARE reserved reserved reserved -ARRAY reserved reserved reserved -ARRAY_AGG reserved reserved -ARRAY_MAX_CARDINALITY reserved -AS reserved reserved reserved reserved -ASC reserved non-reserved non-reserved reserved -ASENSITIVE reserved reserved -ASSERTION non-reserved non-reserved non-reserved reserved -ASSIGNMENT non-reserved non-reserved non-reserved -ASYMMETRIC reserved reserved reserved -AT non-reserved reserved reserved reserved -ATOMIC reserved reserved -ATTRIBUTE non-reserved non-reserved non-reserved -ATTRIBUTES non-reserved non-reserved -AUTHORIZATION reserved (can be function or type) reserved reserved reserved -AVG reserved reserved reserved -BACKWARD non-reserved -BASE64 non-reserved non-reserved -BEFORE non-reserved non-reserved non-reserved -BEGIN non-reserved reserved reserved reserved -BEGIN_FRAME reserved -BEGIN_PARTITION reserved -BERNOULLI non-reserved non-reserved -BETWEEN non-reserved (cannot be function or type) reserved reserved reserved -BIGINT non-reserved (cannot be function or type) reserved reserved -BINARY reserved (can be function or type) reserved reserved -BIT non-reserved (cannot be function or type) reserved -BIT_LENGTH reserved -BLOB reserved reserved -BLOCKED non-reserved non-reserved -BOM non-reserved non-reserved -BOOLEAN non-reserved (cannot be function or type) reserved reserved -BOTH reserved reserved reserved reserved -BREADTH non-reserved non-reserved -BY non-reserved reserved reserved reserved -C non-reserved non-reserved non-reserved -CACHE non-reserved -CALL reserved reserved -CALLED non-reserved reserved reserved -CARDINALITY reserved reserved -CASCADE non-reserved non-reserved non-reserved reserved -CASCADED non-reserved reserved reserved reserved -CASE reserved reserved reserved reserved -CAST reserved reserved reserved reserved -CATALOG non-reserved non-reserved non-reserved reserved -CATALOG_NAME non-reserved non-reserved non-reserved -CEIL reserved reserved -CEILING reserved reserved -CHAIN non-reserved non-reserved non-reserved -CHAR non-reserved (cannot be function or type) reserved reserved reserved -CHARACTER non-reserved (cannot be function or type) reserved reserved reserved -CHARACTERISTICS non-reserved non-reserved non-reserved -CHARACTERS non-reserved non-reserved -CHARACTER_LENGTH reserved reserved reserved -CHARACTER_SET_CATALOG non-reserved non-reserved non-reserved -CHARACTER_SET_NAME non-reserved non-reserved non-reserved -CHARACTER_SET_SCHEMA non-reserved non-reserved non-reserved -CHAR_LENGTH reserved reserved reserved -CHECK reserved reserved reserved reserved -CHECKPOINT non-reserved -CLASS non-reserved -CLASS_ORIGIN non-reserved non-reserved non-reserved -CLOB reserved reserved -CLOSE non-reserved reserved reserved reserved -CLUSTER non-reserved -COALESCE non-reserved (cannot be function or type) reserved reserved reserved -COBOL non-reserved non-reserved non-reserved -COLLATE reserved reserved reserved reserved -COLLATION reserved (can be function or type) non-reserved non-reserved reserved -COLLATION_CATALOG non-reserved non-reserved non-reserved -COLLATION_NAME non-reserved non-reserved non-reserved -COLLATION_SCHEMA non-reserved non-reserved non-reserved -COLLECT reserved reserved -COLUMN reserved reserved reserved reserved -COLUMNS non-reserved non-reserved -COLUMN_NAME non-reserved non-reserved non-reserved -COMMAND_FUNCTION non-reserved non-reserved non-reserved -COMMAND_FUNCTION_CODE non-reserved non-reserved -COMMENT non-reserved -COMMENTS non-reserved -COMMIT non-reserved reserved reserved reserved -COMMITTED non-reserved non-reserved non-reserved non-reserved -CONCURRENTLY reserved (can be function or type) -CONDITION reserved reserved -CONDITION_NUMBER non-reserved non-reserved non-reserved -CONFIGURATION non-reserved -CONNECT reserved reserved reserved -CONNECTION non-reserved non-reserved non-reserved reserved -CONNECTION_NAME non-reserved non-reserved non-reserved -CONSTRAINT reserved reserved reserved reserved -CONSTRAINTS non-reserved non-reserved non-reserved reserved -CONSTRAINT_CATALOG non-reserved non-reserved non-reserved -CONSTRAINT_NAME non-reserved non-reserved non-reserved -CONSTRAINT_SCHEMA non-reserved non-reserved non-reserved -CONSTRUCTOR non-reserved non-reserved -CONTAINS reserved non-reserved -CONTENT non-reserved non-reserved non-reserved -CONTINUE non-reserved non-reserved non-reserved reserved -CONTROL non-reserved non-reserved -CONVERSION non-reserved -CONVERT reserved reserved reserved -COPY non-reserved -CORR reserved reserved -CORRESPONDING reserved reserved reserved -COST non-reserved -COUNT reserved reserved reserved -COVAR_POP reserved reserved -COVAR_SAMP reserved reserved -CREATE reserved reserved reserved reserved -CROSS reserved (can be function or type) reserved reserved reserved -CSV non-reserved -CUBE reserved reserved -CUME_DIST reserved reserved -CURRENT non-reserved reserved reserved reserved -CURRENT_CATALOG reserved reserved reserved -CURRENT_DATE reserved reserved reserved reserved -CURRENT_DEFAULT_TRANSFORM_GROUP reserved reserved -CURRENT_PATH reserved reserved -CURRENT_ROLE reserved reserved reserved -CURRENT_ROW reserved -CURRENT_SCHEMA reserved (can be function or type) reserved reserved -CURRENT_TIME reserved reserved reserved reserved -CURRENT_TIMESTAMP reserved reserved reserved reserved -CURRENT_TRANSFORM_GROUP_FOR_TYPE reserved reserved -CURRENT_USER reserved reserved reserved reserved -CURSOR non-reserved reserved reserved reserved -CURSOR_NAME non-reserved non-reserved non-reserved -CYCLE non-reserved reserved reserved -DATA non-reserved non-reserved non-reserved non-reserved -DATABASE non-reserved -DATALINK reserved reserved -DATE reserved reserved reserved -DATETIME_INTERVAL_CODE non-reserved non-reserved non-reserved -DATETIME_INTERVAL_PRECISION non-reserved non-reserved non-reserved -DAY non-reserved reserved reserved reserved -DB non-reserved non-reserved -DEALLOCATE non-reserved reserved reserved reserved -DEC non-reserved (cannot be function or type) reserved reserved reserved -DECIMAL non-reserved (cannot be function or type) reserved reserved reserved -DECLARE non-reserved reserved reserved reserved -DEFAULT reserved reserved reserved reserved -DEFAULTS non-reserved non-reserved non-reserved -DEFERRABLE reserved non-reserved non-reserved reserved -DEFERRED non-reserved non-reserved non-reserved reserved -DEFINED non-reserved non-reserved -DEFINER non-reserved non-reserved non-reserved -DEGREE non-reserved non-reserved -DELETE non-reserved reserved reserved reserved -DELIMITER non-reserved -DELIMITERS non-reserved -DENSE_RANK reserved reserved -DEPTH non-reserved non-reserved -DEREF reserved reserved -DERIVED non-reserved non-reserved -DESC reserved non-reserved non-reserved reserved -DESCRIBE reserved reserved reserved -DESCRIPTOR non-reserved non-reserved reserved -DETERMINISTIC reserved reserved -DIAGNOSTICS non-reserved non-reserved reserved -DICTIONARY non-reserved -DISABLE non-reserved -DISCARD non-reserved -DISCONNECT reserved reserved reserved -DISPATCH non-reserved non-reserved -DISTINCT reserved reserved reserved reserved -DLNEWCOPY reserved reserved -DLPREVIOUSCOPY reserved reserved -DLURLCOMPLETE reserved reserved -DLURLCOMPLETEONLY reserved reserved -DLURLCOMPLETEWRITE reserved reserved -DLURLPATH reserved reserved -DLURLPATHONLY reserved reserved -DLURLPATHWRITE reserved reserved -DLURLSCHEME reserved reserved -DLURLSERVER reserved reserved -DLVALUE reserved reserved -DO reserved -DOCUMENT non-reserved non-reserved non-reserved -DOMAIN non-reserved non-reserved non-reserved reserved -DOUBLE non-reserved reserved reserved reserved -DROP non-reserved reserved reserved reserved -DYNAMIC reserved reserved -DYNAMIC_FUNCTION non-reserved non-reserved non-reserved -DYNAMIC_FUNCTION_CODE non-reserved non-reserved -EACH non-reserved reserved reserved -ELEMENT reserved reserved -ELSE reserved reserved reserved reserved -EMPTY non-reserved non-reserved -ENABLE non-reserved -ENCODING non-reserved non-reserved non-reserved -ENCRYPTED non-reserved -END reserved reserved reserved reserved -END-EXEC reserved reserved reserved -END_FRAME reserved -END_PARTITION reserved -ENFORCED non-reserved -ENUM non-reserved -EQUALS reserved non-reserved -ESCAPE non-reserved reserved reserved reserved -EVENT non-reserved -EVERY reserved reserved -EXCEPT reserved reserved reserved reserved -EXCEPTION reserved -EXCLUDE non-reserved non-reserved non-reserved -EXCLUDING non-reserved non-reserved non-reserved -EXCLUSIVE non-reserved -EXEC reserved reserved reserved -EXECUTE non-reserved reserved reserved reserved -EXISTS non-reserved (cannot be function or type) reserved reserved reserved -EXP reserved reserved -EXPLAIN non-reserved -EXPRESSION non-reserved -EXTENSION non-reserved -EXTERNAL non-reserved reserved reserved reserved -EXTRACT non-reserved (cannot be function or type) reserved reserved reserved -FALSE reserved reserved reserved reserved -FAMILY non-reserved -FETCH reserved reserved reserved reserved -FILE non-reserved non-reserved -FILTER reserved reserved -FINAL non-reserved non-reserved -FIRST non-reserved non-reserved non-reserved reserved -FIRST_VALUE reserved reserved -FLAG non-reserved non-reserved -FLOAT non-reserved (cannot be function or type) reserved reserved reserved -FLOOR reserved reserved -FOLLOWING non-reserved non-reserved non-reserved -FOR reserved reserved reserved reserved -FORCE non-reserved -FOREIGN reserved reserved reserved reserved -FORTRAN non-reserved non-reserved non-reserved -FORWARD non-reserved -FOUND non-reserved non-reserved reserved -FRAME_ROW reserved -FREE reserved reserved -FREEZE reserved (can be function or type) -FROM reserved reserved reserved reserved -FS non-reserved non-reserved -FULL reserved (can be function or type) reserved reserved reserved -FUNCTION non-reserved reserved reserved -FUNCTIONS non-reserved -FUSION reserved reserved -G non-reserved non-reserved -GENERAL non-reserved non-reserved -GENERATED non-reserved non-reserved -GET reserved reserved reserved -GLOBAL non-reserved reserved reserved reserved -GO non-reserved non-reserved reserved -GOTO non-reserved non-reserved reserved -GRANT reserved reserved reserved reserved -GRANTED non-reserved non-reserved non-reserved -GREATEST non-reserved (cannot be function or type) -GROUP reserved reserved reserved reserved -GROUPING reserved reserved -GROUPS reserved -HANDLER non-reserved -HAVING reserved reserved reserved reserved -HEADER non-reserved -HEX non-reserved non-reserved -HIERARCHY non-reserved non-reserved -HOLD non-reserved reserved reserved -HOUR non-reserved reserved reserved reserved -ID non-reserved non-reserved -IDENTITY non-reserved reserved reserved reserved -IF non-reserved -IGNORE non-reserved non-reserved -ILIKE reserved (can be function or type) -IMMEDIATE non-reserved non-reserved non-reserved reserved -IMMEDIATELY non-reserved -IMMUTABLE non-reserved -IMPLEMENTATION non-reserved non-reserved -IMPLICIT non-reserved -IMPORT reserved reserved -IN reserved reserved reserved reserved -INCLUDING non-reserved non-reserved non-reserved -INCREMENT non-reserved non-reserved non-reserved -INDENT non-reserved non-reserved -INDEX non-reserved -INDEXES non-reserved -INDICATOR reserved reserved reserved -INHERIT non-reserved -INHERITS non-reserved -INITIALLY reserved non-reserved non-reserved reserved -INLINE non-reserved -INNER reserved (can be function or type) reserved reserved reserved -INOUT non-reserved (cannot be function or type) reserved reserved -INPUT non-reserved non-reserved non-reserved reserved -INSENSITIVE non-reserved reserved reserved reserved -INSERT non-reserved reserved reserved reserved -INSTANCE non-reserved non-reserved -INSTANTIABLE non-reserved non-reserved -INSTEAD non-reserved non-reserved non-reserved -INT non-reserved (cannot be function or type) reserved reserved reserved -INTEGER non-reserved (cannot be function or type) reserved reserved reserved -INTEGRITY non-reserved non-reserved -INTERSECT reserved reserved reserved reserved -INTERSECTION reserved reserved -INTERVAL non-reserved (cannot be function or type) reserved reserved reserved -INTO reserved reserved reserved reserved -INVOKER non-reserved non-reserved non-reserved -IS reserved (can be function or type) reserved reserved reserved -ISNULL reserved (can be function or type) -ISOLATION non-reserved non-reserved non-reserved reserved -JOIN reserved (can be function or type) reserved reserved reserved -K non-reserved non-reserved -KEY non-reserved non-reserved non-reserved reserved -KEY_MEMBER non-reserved non-reserved -KEY_TYPE non-reserved non-reserved -LABEL non-reserved -LAG reserved reserved -LANGUAGE non-reserved reserved reserved reserved -LARGE non-reserved reserved reserved -LAST non-reserved non-reserved non-reserved reserved -LAST_VALUE reserved reserved -LATERAL reserved reserved reserved -LC_COLLATE non-reserved -LC_CTYPE non-reserved -LEAD reserved reserved -LEADING reserved reserved reserved reserved -LEAKPROOF non-reserved -LEAST non-reserved (cannot be function or type) -LEFT reserved (can be function or type) reserved reserved reserved -LENGTH non-reserved non-reserved non-reserved -LEVEL non-reserved non-reserved non-reserved reserved -LIBRARY non-reserved non-reserved -LIKE reserved (can be function or type) reserved reserved reserved -LIKE_REGEX reserved reserved -LIMIT reserved non-reserved non-reserved -LINK non-reserved non-reserved -LISTEN non-reserved -LN reserved reserved -LOAD non-reserved -LOCAL non-reserved reserved reserved reserved -LOCALTIME reserved reserved reserved -LOCALTIMESTAMP reserved reserved reserved -LOCATION non-reserved non-reserved non-reserved -LOCATOR non-reserved non-reserved -LOCK non-reserved -LOWER reserved reserved reserved -M non-reserved non-reserved -MAP non-reserved non-reserved -MAPPING non-reserved non-reserved non-reserved -MATCH non-reserved reserved reserved reserved -MATCHED non-reserved non-reserved -MATERIALIZED non-reserved -MAX reserved reserved reserved -MAXVALUE non-reserved non-reserved non-reserved -MAX_CARDINALITY reserved -MEMBER reserved reserved -MERGE reserved reserved -MESSAGE_LENGTH non-reserved non-reserved non-reserved -MESSAGE_OCTET_LENGTH non-reserved non-reserved non-reserved -MESSAGE_TEXT non-reserved non-reserved non-reserved -METHOD reserved reserved -MIN reserved reserved reserved -MINUTE non-reserved reserved reserved reserved -MINVALUE non-reserved non-reserved non-reserved -MOD reserved reserved -MODE non-reserved -MODIFIES reserved reserved -MODULE reserved reserved reserved -MONTH non-reserved reserved reserved reserved -MORE non-reserved non-reserved non-reserved -MOVE non-reserved -MULTISET reserved reserved -MUMPS non-reserved non-reserved non-reserved -NAME non-reserved non-reserved non-reserved non-reserved -NAMES non-reserved non-reserved non-reserved reserved -NAMESPACE non-reserved non-reserved -NATIONAL non-reserved (cannot be function or type) reserved reserved reserved -NATURAL reserved (can be function or type) reserved reserved reserved -NCHAR non-reserved (cannot be function or type) reserved reserved reserved -NCLOB reserved reserved -NESTING non-reserved non-reserved -NEW reserved reserved -NEXT non-reserved non-reserved non-reserved reserved -NFC non-reserved non-reserved -NFD non-reserved non-reserved -NFKC non-reserved non-reserved -NFKD non-reserved non-reserved -NIL non-reserved non-reserved -NO non-reserved reserved reserved reserved -NONE non-reserved (cannot be function or type) reserved reserved -NORMALIZE reserved reserved -NORMALIZED non-reserved non-reserved -NOT reserved reserved reserved reserved -NOTHING non-reserved -NOTIFY non-reserved -NOTNULL reserved (can be function or type) -NOWAIT non-reserved -NTH_VALUE reserved reserved -NTILE reserved reserved -NULL reserved reserved reserved reserved -NULLABLE non-reserved non-reserved non-reserved -NULLIF non-reserved (cannot be function or type) reserved reserved reserved -NULLS non-reserved non-reserved non-reserved -NUMBER non-reserved non-reserved non-reserved -NUMERIC non-reserved (cannot be function or type) reserved reserved reserved -OBJECT non-reserved non-reserved non-reserved -OCCURRENCES_REGEX reserved reserved -OCTETS non-reserved non-reserved -OCTET_LENGTH reserved reserved reserved -OF non-reserved reserved reserved reserved -OFF non-reserved non-reserved non-reserved -OFFSET reserved reserved reserved -OIDS non-reserved -OLD reserved reserved -ON reserved reserved reserved reserved -ONLY reserved reserved reserved reserved -OPEN reserved reserved reserved -OPERATOR non-reserved -OPTION non-reserved non-reserved non-reserved reserved -OPTIONS non-reserved non-reserved non-reserved -OR reserved reserved reserved reserved -ORDER reserved reserved reserved reserved -ORDERING non-reserved non-reserved -ORDINALITY non-reserved non-reserved -OTHERS non-reserved non-reserved -OUT non-reserved (cannot be function or type) reserved reserved -OUTER reserved (can be function or type) reserved reserved reserved -OUTPUT non-reserved non-reserved reserved -OVER reserved (can be function or type) reserved reserved -OVERLAPS reserved (can be function or type) reserved reserved reserved -OVERLAY non-reserved (cannot be function or type) reserved reserved -OVERRIDING non-reserved non-reserved -OWNED non-reserved -OWNER non-reserved -P non-reserved non-reserved -PAD non-reserved non-reserved reserved -PARAMETER reserved reserved -PARAMETER_MODE non-reserved non-reserved -PARAMETER_NAME non-reserved non-reserved -PARAMETER_ORDINAL_POSITION non-reserved non-reserved -PARAMETER_SPECIFIC_CATALOG non-reserved non-reserved -PARAMETER_SPECIFIC_NAME non-reserved non-reserved -PARAMETER_SPECIFIC_SCHEMA non-reserved non-reserved -PARSER non-reserved -PARTIAL non-reserved non-reserved non-reserved reserved -PARTITION non-reserved reserved reserved -PASCAL non-reserved non-reserved non-reserved -PASSING non-reserved non-reserved non-reserved -PASSTHROUGH non-reserved non-reserved -PASSWORD non-reserved -PATH non-reserved non-reserved -PERCENT reserved -PERCENTILE_CONT reserved reserved -PERCENTILE_DISC reserved reserved -PERCENT_RANK reserved reserved -PERIOD reserved -PERMISSION non-reserved non-reserved -PLACING reserved non-reserved non-reserved -PLANS non-reserved -PLI non-reserved non-reserved non-reserved -PORTION reserved -POSITION non-reserved (cannot be function or type) reserved reserved reserved -POSITION_REGEX reserved reserved -POWER reserved reserved -PRECEDES reserved -PRECEDING non-reserved non-reserved non-reserved -PRECISION non-reserved (cannot be function or type) reserved reserved reserved -PREPARE non-reserved reserved reserved reserved -PREPARED non-reserved -PRESERVE non-reserved non-reserved non-reserved reserved -PRIMARY reserved reserved reserved reserved -PRIOR non-reserved non-reserved non-reserved reserved -PRIVILEGES non-reserved non-reserved non-reserved reserved -PROCEDURAL non-reserved -PROCEDURE non-reserved reserved reserved reserved -PROGRAM non-reserved -PUBLIC non-reserved non-reserved reserved -QUOTE non-reserved -RANGE non-reserved reserved reserved -RANK reserved reserved -READ non-reserved non-reserved non-reserved reserved -READS reserved reserved -REAL non-reserved (cannot be function or type) reserved reserved reserved -REASSIGN non-reserved -RECHECK non-reserved -RECOVERY non-reserved non-reserved -RECURSIVE non-reserved reserved reserved -REF non-reserved reserved reserved -REFERENCES reserved reserved reserved reserved -REFERENCING reserved reserved -REFRESH non-reserved -REGR_AVGX reserved reserved -REGR_AVGY reserved reserved -REGR_COUNT reserved reserved -REGR_INTERCEPT reserved reserved -REGR_R2 reserved reserved -REGR_SLOPE reserved reserved -REGR_SXX reserved reserved -REGR_SXY reserved reserved -REGR_SYY reserved reserved -REINDEX non-reserved -RELATIVE non-reserved non-reserved non-reserved reserved -RELEASE non-reserved reserved reserved -RENAME non-reserved -REPEATABLE non-reserved non-reserved non-reserved non-reserved -REPLACE non-reserved -REPLICA non-reserved -REQUIRING non-reserved non-reserved -RESET non-reserved -RESPECT non-reserved non-reserved -RESTART non-reserved non-reserved non-reserved -RESTORE non-reserved non-reserved -RESTRICT non-reserved non-reserved non-reserved reserved -RESULT reserved reserved -RETURN reserved reserved -RETURNED_CARDINALITY non-reserved non-reserved -RETURNED_LENGTH non-reserved non-reserved non-reserved -RETURNED_OCTET_LENGTH non-reserved non-reserved non-reserved -RETURNED_SQLSTATE non-reserved non-reserved non-reserved -RETURNING reserved non-reserved non-reserved -RETURNS non-reserved reserved reserved -REVOKE non-reserved reserved reserved reserved -RIGHT reserved (can be function or type) reserved reserved reserved -ROLE non-reserved non-reserved non-reserved -ROLLBACK non-reserved reserved reserved reserved -ROLLUP reserved reserved -ROUTINE non-reserved non-reserved -ROUTINE_CATALOG non-reserved non-reserved -ROUTINE_NAME non-reserved non-reserved -ROUTINE_SCHEMA non-reserved non-reserved -ROW non-reserved (cannot be function or type) reserved reserved -ROWS non-reserved reserved reserved reserved -ROW_COUNT non-reserved non-reserved non-reserved -ROW_NUMBER reserved reserved -RULE non-reserved -SAVEPOINT non-reserved reserved reserved -SCALE non-reserved non-reserved non-reserved -SCHEMA non-reserved non-reserved non-reserved reserved -SCHEMA_NAME non-reserved non-reserved non-reserved -SCOPE reserved reserved -SCOPE_CATALOG non-reserved non-reserved -SCOPE_NAME non-reserved non-reserved -SCOPE_SCHEMA non-reserved non-reserved -SCROLL non-reserved reserved reserved reserved -SEARCH non-reserved reserved reserved -SECOND non-reserved reserved reserved reserved -SECTION non-reserved non-reserved reserved -SECURITY non-reserved non-reserved non-reserved -SELECT reserved reserved reserved reserved -SELECTIVE non-reserved non-reserved -SELF non-reserved non-reserved -SENSITIVE reserved reserved -SEQUENCE non-reserved non-reserved non-reserved -SEQUENCES non-reserved -SERIALIZABLE non-reserved non-reserved non-reserved non-reserved -SERVER non-reserved non-reserved non-reserved -SERVER_NAME non-reserved non-reserved non-reserved -SESSION non-reserved non-reserved non-reserved reserved -SESSION_USER reserved reserved reserved reserved -SET non-reserved reserved reserved reserved -SETOF non-reserved (cannot be function or type) -SETS non-reserved non-reserved -SHARE non-reserved -SHOW non-reserved -SIMILAR reserved (can be function or type) reserved reserved -SIMPLE non-reserved non-reserved non-reserved -SIZE non-reserved non-reserved reserved -SMALLINT non-reserved (cannot be function or type) reserved reserved reserved -SNAPSHOT non-reserved -SOME reserved reserved reserved reserved -SOURCE non-reserved non-reserved -SPACE non-reserved non-reserved reserved -SPECIFIC reserved reserved -SPECIFICTYPE reserved reserved -SPECIFIC_NAME non-reserved non-reserved -SQL reserved reserved reserved -SQLCODE reserved -SQLERROR reserved -SQLEXCEPTION reserved reserved -SQLSTATE reserved reserved reserved -SQLWARNING reserved reserved -SQRT reserved reserved -STABLE non-reserved -STANDALONE non-reserved non-reserved non-reserved -START non-reserved reserved reserved -STATE non-reserved non-reserved -STATEMENT non-reserved non-reserved non-reserved -STATIC reserved reserved -STATISTICS non-reserved -STDDEV_POP reserved reserved -STDDEV_SAMP reserved reserved -STDIN non-reserved -STDOUT non-reserved -STORAGE non-reserved -STRICT non-reserved -STRIP non-reserved non-reserved non-reserved -STRUCTURE non-reserved non-reserved -STYLE non-reserved non-reserved -SUBCLASS_ORIGIN non-reserved non-reserved non-reserved -SUBMULTISET reserved reserved -SUBSTRING non-reserved (cannot be function or type) reserved reserved reserved -SUBSTRING_REGEX reserved reserved -SUCCEEDS reserved -SUM reserved reserved reserved -SYMMETRIC reserved reserved reserved -SYSID non-reserved -SYSTEM non-reserved reserved reserved -SYSTEM_TIME reserved -SYSTEM_USER reserved reserved reserved -T non-reserved non-reserved -TABLE reserved reserved reserved reserved -TABLES non-reserved -TABLESAMPLE reserved reserved -TABLESPACE non-reserved -TABLE_NAME non-reserved non-reserved non-reserved -TEMP non-reserved -TEMPLATE non-reserved -TEMPORARY non-reserved non-reserved non-reserved reserved -TEXT non-reserved -THEN reserved reserved reserved reserved -TIES non-reserved non-reserved -TIME non-reserved (cannot be function or type) reserved reserved reserved -TIMESTAMP non-reserved (cannot be function or type) reserved reserved reserved -TIMEZONE_HOUR reserved reserved reserved -TIMEZONE_MINUTE reserved reserved reserved -TO reserved reserved reserved reserved -TOKEN non-reserved non-reserved -TOP_LEVEL_COUNT non-reserved non-reserved -TRAILING reserved reserved reserved reserved -TRANSACTION non-reserved non-reserved non-reserved reserved -TRANSACTIONS_COMMITTED non-reserved non-reserved -TRANSACTIONS_ROLLED_BACK non-reserved non-reserved -TRANSACTION_ACTIVE non-reserved non-reserved -TRANSFORM non-reserved non-reserved -TRANSFORMS non-reserved non-reserved -TRANSLATE reserved reserved reserved -TRANSLATE_REGEX reserved reserved -TRANSLATION reserved reserved reserved -TREAT non-reserved (cannot be function or type) reserved reserved -TRIGGER non-reserved reserved reserved -TRIGGER_CATALOG non-reserved non-reserved -TRIGGER_NAME non-reserved non-reserved -TRIGGER_SCHEMA non-reserved non-reserved -TRIM non-reserved (cannot be function or type) reserved reserved reserved -TRIM_ARRAY reserved reserved -TRUE reserved reserved reserved reserved -TRUNCATE non-reserved reserved reserved -TRUSTED non-reserved -TYPE non-reserved non-reserved non-reserved non-reserved -TYPES non-reserved -UESCAPE reserved reserved -UNBOUNDED non-reserved non-reserved non-reserved -UNCOMMITTED non-reserved non-reserved non-reserved non-reserved -UNDER non-reserved non-reserved -UNENCRYPTED non-reserved -UNION reserved reserved reserved reserved -UNIQUE reserved reserved reserved reserved -UNKNOWN non-reserved reserved reserved reserved -UNLINK non-reserved non-reserved -UNLISTEN non-reserved -UNLOGGED non-reserved -UNNAMED non-reserved non-reserved non-reserved -UNNEST reserved reserved -UNTIL non-reserved -UNTYPED non-reserved non-reserved -UPDATE non-reserved reserved reserved reserved -UPPER reserved reserved reserved -URI non-reserved non-reserved -USAGE non-reserved non-reserved reserved -USER reserved reserved reserved reserved -USER_DEFINED_TYPE_CATALOG non-reserved non-reserved -USER_DEFINED_TYPE_CODE non-reserved non-reserved -USER_DEFINED_TYPE_NAME non-reserved non-reserved -USER_DEFINED_TYPE_SCHEMA non-reserved non-reserved -USING reserved reserved reserved reserved -VACUUM non-reserved -VALID non-reserved non-reserved non-reserved -VALIDATE non-reserved -VALIDATOR non-reserved -VALUE non-reserved reserved reserved reserved -VALUES non-reserved (cannot be function or type) reserved reserved reserved -VALUE_OF reserved -VARBINARY reserved reserved -VARCHAR non-reserved (cannot be function or type) reserved reserved reserved -VARIADIC reserved -VARYING non-reserved reserved reserved reserved -VAR_POP reserved reserved -VAR_SAMP reserved reserved -VERBOSE reserved (can be function or type) -VERSION non-reserved non-reserved non-reserved -VERSIONING reserved -VIEW non-reserved non-reserved non-reserved reserved -VOLATILE non-reserved -WHEN reserved reserved reserved reserved -WHENEVER reserved reserved reserved -WHERE reserved reserved reserved reserved -WHITESPACE non-reserved non-reserved non-reserved -WIDTH_BUCKET reserved reserved -WINDOW reserved reserved reserved -WITH reserved reserved reserved reserved -WITHIN reserved reserved -WITHOUT non-reserved reserved reserved -WORK non-reserved non-reserved non-reserved reserved -WRAPPER non-reserved non-reserved non-reserved -WRITE non-reserved non-reserved non-reserved reserved -XML non-reserved reserved reserved -XMLAGG reserved reserved -XMLATTRIBUTES non-reserved (cannot be function or type) reserved reserved -XMLBINARY reserved reserved -XMLCAST reserved reserved -XMLCOMMENT reserved reserved -XMLCONCAT non-reserved (cannot be function or type) reserved reserved -XMLDECLARATION non-reserved non-reserved -XMLDOCUMENT reserved reserved -XMLELEMENT non-reserved (cannot be function or type) reserved reserved -XMLEXISTS non-reserved (cannot be function or type) reserved reserved -XMLFOREST non-reserved (cannot be function or type) reserved reserved -XMLITERATE reserved reserved -XMLNAMESPACES reserved reserved -XMLPARSE non-reserved (cannot be function or type) reserved reserved -XMLPI non-reserved (cannot be function or type) reserved reserved -XMLQUERY reserved reserved -XMLROOT non-reserved (cannot be function or type) -XMLSCHEMA non-reserved non-reserved -XMLSERIALIZE non-reserved (cannot be function or type) reserved reserved -XMLTABLE reserved reserved -XMLTEXT reserved reserved -XMLVALIDATE reserved reserved -YEAR non-reserved reserved reserved reserved -YES non-reserved non-reserved non-reserved -ZONE non-reserved non-reserved non-reserved reserved \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/processors.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/processors.go deleted file mode 100644 index dcd9c6ac0..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/processors.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -// BeforeInsertProcessor executed before an object is initially persisted to the database -type BeforeInsertProcessor interface { - BeforeInsert() -} - -// BeforeUpdateProcessor executed before an object is updated -type BeforeUpdateProcessor interface { - BeforeUpdate() -} - -// BeforeDeleteProcessor executed before an object is deleted -type BeforeDeleteProcessor interface { - BeforeDelete() -} - -// BeforeSetProcessor executed before data set to the struct fields -type BeforeSetProcessor interface { - BeforeSet(string, Cell) -} - -// AfterSetProcessor executed after data set to the struct fields -type AfterSetProcessor interface { - AfterSet(string, Cell) -} - -// AfterInsertProcessor executed after an object is persisted to the database -type AfterInsertProcessor interface { - AfterInsert() -} - -// AfterUpdateProcessor executed after an object has been updated -type AfterUpdateProcessor interface { - AfterUpdate() -} - -// AfterDeleteProcessor executed after an object has been deleted -type AfterDeleteProcessor interface { - AfterDelete() -} - -// AfterLoadProcessor executed after an ojbect has been loaded from database -type AfterLoadProcessor interface { - AfterLoad() -} - -// AfterLoadSessionProcessor executed after an ojbect has been loaded from database with session parameter -type AfterLoadSessionProcessor interface { - AfterLoad(*Session) -} - -type executedProcessorFunc func(*Session, interface{}) error - -type executedProcessor struct { - fun executedProcessorFunc - session *Session - bean interface{} -} - -func (executor *executedProcessor) execute() error { - return executor.fun(executor.session, executor.bean) -} - -func (session *Session) executeProcessors() error { - processors := session.afterProcessors - session.afterProcessors = make([]executedProcessor, 0) - for _, processor := range processors { - if err := processor.execute(); err != nil { - return err - } - } - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/rows.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/rows.go deleted file mode 100644 index bdd44589f..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/rows.go +++ /dev/null @@ -1,121 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "fmt" - "reflect" - - "xorm.io/core" -) - -// Rows rows wrapper a rows to -type Rows struct { - session *Session - rows *core.Rows - beanType reflect.Type - lastError error -} - -func newRows(session *Session, bean interface{}) (*Rows, error) { - rows := new(Rows) - rows.session = session - rows.beanType = reflect.Indirect(reflect.ValueOf(bean)).Type() - - var sqlStr string - var args []interface{} - var err error - - if err = rows.session.statement.setRefBean(bean); err != nil { - return nil, err - } - - if len(session.statement.TableName()) <= 0 { - return nil, ErrTableNotFound - } - - if rows.session.statement.RawSQL == "" { - sqlStr, args, err = rows.session.statement.genGetSQL(bean) - if err != nil { - return nil, err - } - } else { - sqlStr = rows.session.statement.RawSQL - args = rows.session.statement.RawParams - } - - rows.rows, err = rows.session.queryRows(sqlStr, args...) - if err != nil { - rows.lastError = err - rows.Close() - return nil, err - } - - return rows, nil -} - -// Next move cursor to next record, return false if end has reached -func (rows *Rows) Next() bool { - if rows.lastError == nil && rows.rows != nil { - hasNext := rows.rows.Next() - if !hasNext { - rows.lastError = sql.ErrNoRows - } - return hasNext - } - return false -} - -// Err returns the error, if any, that was encountered during iteration. Err may be called after an explicit or implicit Close. -func (rows *Rows) Err() error { - return rows.lastError -} - -// Scan row record to bean properties -func (rows *Rows) Scan(bean interface{}) error { - if rows.lastError != nil { - return rows.lastError - } - - if reflect.Indirect(reflect.ValueOf(bean)).Type() != rows.beanType { - return fmt.Errorf("scan arg is incompatible type to [%v]", rows.beanType) - } - - if err := rows.session.statement.setRefBean(bean); err != nil { - return err - } - - fields, err := rows.rows.Columns() - if err != nil { - return err - } - - scanResults, err := rows.session.row2Slice(rows.rows, fields, bean) - if err != nil { - return err - } - - dataStruct := rValue(bean) - _, err = rows.session.slice2Bean(scanResults, fields, bean, &dataStruct, rows.session.statement.RefTable) - if err != nil { - return err - } - - return rows.session.executeProcessors() -} - -// Close session if session.IsAutoClose is true, and claimed any opened resources -func (rows *Rows) Close() error { - if rows.session.isAutoClose { - defer rows.session.Close() - } - - if rows.rows != nil { - return rows.rows.Close() - } - - return rows.lastError -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/rows_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/rows_test.go deleted file mode 100644 index af3338619..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/rows_test.go +++ /dev/null @@ -1,150 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestRows(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type UserRows struct { - Id int64 - IsMan bool - } - - assert.NoError(t, testEngine.Sync2(new(UserRows))) - - cnt, err := testEngine.Insert(&UserRows{ - IsMan: true, - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - rows, err := testEngine.Rows(new(UserRows)) - assert.NoError(t, err) - defer rows.Close() - - cnt = 0 - user := new(UserRows) - for rows.Next() { - err = rows.Scan(user) - assert.NoError(t, err) - cnt++ - } - assert.EqualValues(t, 1, cnt) - assert.False(t, rows.Next()) - assert.NoError(t, rows.Close()) - - rows0, err := testEngine.Where("1>1").Rows(new(UserRows)) - assert.NoError(t, err) - defer rows0.Close() - - cnt = 0 - user0 := new(UserRows) - for rows0.Next() { - err = rows0.Scan(user0) - assert.NoError(t, err) - cnt++ - } - assert.EqualValues(t, 0, cnt) - assert.NoError(t, rows0.Close()) - - sess := testEngine.NewSession() - defer sess.Close() - - rows1, err := sess.Prepare().Rows(new(UserRows)) - assert.NoError(t, err) - defer rows1.Close() - - cnt = 0 - for rows1.Next() { - err = rows1.Scan(user) - assert.NoError(t, err) - cnt++ - } - assert.EqualValues(t, 1, cnt) - - var tbName = testEngine.Quote(testEngine.TableName(user, true)) - rows2, err := testEngine.SQL("SELECT * FROM " + tbName).Rows(new(UserRows)) - assert.NoError(t, err) - defer rows2.Close() - - cnt = 0 - for rows2.Next() { - err = rows2.Scan(user) - assert.NoError(t, err) - cnt++ - } - assert.EqualValues(t, 1, cnt) -} - -func TestRowsMyTableName(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type UserRowsMyTable struct { - Id int64 - IsMan bool - } - - var tableName = "user_rows_my_table_name" - - assert.NoError(t, testEngine.Table(tableName).Sync2(new(UserRowsMyTable))) - - cnt, err := testEngine.Table(tableName).Insert(&UserRowsMyTable{ - IsMan: true, - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - rows, err := testEngine.Table(tableName).Rows(new(UserRowsMyTable)) - assert.NoError(t, err) - defer rows.Close() - - cnt = 0 - user := new(UserRowsMyTable) - for rows.Next() { - err = rows.Scan(user) - assert.NoError(t, err) - cnt++ - } - assert.EqualValues(t, 1, cnt) -} - -type UserRowsSpecTable struct { - Id int64 - IsMan bool -} - -func (UserRowsSpecTable) TableName() string { - return "user_rows_my_table_name" -} - -func TestRowsSpecTableName(t *testing.T) { - assert.NoError(t, prepareEngine()) - assert.NoError(t, testEngine.Sync2(new(UserRowsSpecTable))) - - cnt, err := testEngine.Insert(&UserRowsSpecTable{ - IsMan: true, - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - rows, err := testEngine.Rows(new(UserRowsSpecTable)) - assert.NoError(t, err) - defer rows.Close() - - cnt = 0 - user := new(UserRowsSpecTable) - for rows.Next() { - err = rows.Scan(user) - assert.NoError(t, err) - cnt++ - } - assert.EqualValues(t, 1, cnt) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session.go deleted file mode 100644 index b33955fdc..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session.go +++ /dev/null @@ -1,866 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "context" - "database/sql" - "errors" - "fmt" - "hash/crc32" - "reflect" - "strings" - "time" - - "xorm.io/core" -) - -type sessionType int - -const ( - engineSession sessionType = iota - groupSession -) - -// Session keep a pointer to sql.DB and provides all execution of all -// kind of database operations. -type Session struct { - db *core.DB - engine *Engine - tx *core.Tx - statement Statement - isAutoCommit bool - isCommitedOrRollbacked bool - isAutoClose bool - - // Automatically reset the statement after operations that execute a SQL - // query such as Count(), Find(), Get(), ... - autoResetStatement bool - - // !nashtsai! storing these beans due to yet committed tx - afterInsertBeans map[interface{}]*[]func(interface{}) - afterUpdateBeans map[interface{}]*[]func(interface{}) - afterDeleteBeans map[interface{}]*[]func(interface{}) - // -- - - beforeClosures []func(interface{}) - afterClosures []func(interface{}) - - afterProcessors []executedProcessor - - prepareStmt bool - stmtCache map[uint32]*core.Stmt //key: hash.Hash32 of (queryStr, len(queryStr)) - - // !evalphobia! stored the last executed query on this session - //beforeSQLExec func(string, ...interface{}) - lastSQL string - lastSQLArgs []interface{} - - ctx context.Context - sessionType sessionType -} - -// Clone copy all the session's content and return a new session -func (session *Session) Clone() *Session { - var sess = *session - return &sess -} - -// Init reset the session as the init status. -func (session *Session) Init() { - session.statement.Init() - session.statement.Engine = session.engine - session.isAutoCommit = true - session.isCommitedOrRollbacked = false - session.isAutoClose = false - session.autoResetStatement = true - session.prepareStmt = false - - // !nashtsai! is lazy init better? - session.afterInsertBeans = make(map[interface{}]*[]func(interface{}), 0) - session.afterUpdateBeans = make(map[interface{}]*[]func(interface{}), 0) - session.afterDeleteBeans = make(map[interface{}]*[]func(interface{}), 0) - session.beforeClosures = make([]func(interface{}), 0) - session.afterClosures = make([]func(interface{}), 0) - session.stmtCache = make(map[uint32]*core.Stmt) - - session.afterProcessors = make([]executedProcessor, 0) - - session.lastSQL = "" - session.lastSQLArgs = []interface{}{} - - session.ctx = session.engine.defaultContext -} - -// Close release the connection from pool -func (session *Session) Close() { - for _, v := range session.stmtCache { - v.Close() - } - - if session.db != nil { - // When Close be called, if session is a transaction and do not call - // Commit or Rollback, then call Rollback. - if session.tx != nil && !session.isCommitedOrRollbacked { - session.Rollback() - } - session.tx = nil - session.stmtCache = nil - session.db = nil - } -} - -// ContextCache enable context cache or not -func (session *Session) ContextCache(context ContextCache) *Session { - session.statement.context = context - return session -} - -// IsClosed returns if session is closed -func (session *Session) IsClosed() bool { - return session.db == nil -} - -func (session *Session) resetStatement() { - if session.autoResetStatement { - session.statement.Init() - } -} - -// Prepare set a flag to session that should be prepare statement before execute query -func (session *Session) Prepare() *Session { - session.prepareStmt = true - return session -} - -// Before Apply before Processor, affected bean is passed to closure arg -func (session *Session) Before(closures func(interface{})) *Session { - if closures != nil { - session.beforeClosures = append(session.beforeClosures, closures) - } - return session -} - -// After Apply after Processor, affected bean is passed to closure arg -func (session *Session) After(closures func(interface{})) *Session { - if closures != nil { - session.afterClosures = append(session.afterClosures, closures) - } - return session -} - -// Table can input a string or pointer to struct for special a table to operate. -func (session *Session) Table(tableNameOrBean interface{}) *Session { - session.statement.Table(tableNameOrBean) - return session -} - -// Alias set the table alias -func (session *Session) Alias(alias string) *Session { - session.statement.Alias(alias) - return session -} - -// NoCascade indicate that no cascade load child object -func (session *Session) NoCascade() *Session { - session.statement.UseCascade = false - return session -} - -// ForUpdate Set Read/Write locking for UPDATE -func (session *Session) ForUpdate() *Session { - session.statement.IsForUpdate = true - return session -} - -// NoAutoCondition disable generate SQL condition from beans -func (session *Session) NoAutoCondition(no ...bool) *Session { - session.statement.NoAutoCondition(no...) - return session -} - -// Limit provide limit and offset query condition -func (session *Session) Limit(limit int, start ...int) *Session { - session.statement.Limit(limit, start...) - return session -} - -// OrderBy provide order by query condition, the input parameter is the content -// after order by on a sql statement. -func (session *Session) OrderBy(order string) *Session { - session.statement.OrderBy(order) - return session -} - -// Desc provide desc order by query condition, the input parameters are columns. -func (session *Session) Desc(colNames ...string) *Session { - session.statement.Desc(colNames...) - return session -} - -// Asc provide asc order by query condition, the input parameters are columns. -func (session *Session) Asc(colNames ...string) *Session { - session.statement.Asc(colNames...) - return session -} - -// StoreEngine is only avialble mysql dialect currently -func (session *Session) StoreEngine(storeEngine string) *Session { - session.statement.StoreEngine = storeEngine - return session -} - -// Charset is only avialble mysql dialect currently -func (session *Session) Charset(charset string) *Session { - session.statement.Charset = charset - return session -} - -// Cascade indicates if loading sub Struct -func (session *Session) Cascade(trueOrFalse ...bool) *Session { - if len(trueOrFalse) >= 1 { - session.statement.UseCascade = trueOrFalse[0] - } - return session -} - -// NoCache ask this session do not retrieve data from cache system and -// get data from database directly. -func (session *Session) NoCache() *Session { - session.statement.UseCache = false - return session -} - -// Join join_operator should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN -func (session *Session) Join(joinOperator string, tablename interface{}, condition string, args ...interface{}) *Session { - session.statement.Join(joinOperator, tablename, condition, args...) - return session -} - -// GroupBy Generate Group By statement -func (session *Session) GroupBy(keys string) *Session { - session.statement.GroupBy(keys) - return session -} - -// Having Generate Having statement -func (session *Session) Having(conditions string) *Session { - session.statement.Having(conditions) - return session -} - -// DB db return the wrapper of sql.DB -func (session *Session) DB() *core.DB { - if session.db == nil { - session.db = session.engine.db - session.stmtCache = make(map[uint32]*core.Stmt, 0) - } - return session.db -} - -func cleanupProcessorsClosures(slices *[]func(interface{})) { - if len(*slices) > 0 { - *slices = make([]func(interface{}), 0) - } -} - -func (session *Session) canCache() bool { - if session.statement.RefTable == nil || - session.statement.JoinStr != "" || - session.statement.RawSQL != "" || - !session.statement.UseCache || - session.statement.IsForUpdate || - session.tx != nil || - len(session.statement.selectStr) > 0 { - return false - } - return true -} - -func (session *Session) doPrepare(db *core.DB, sqlStr string) (stmt *core.Stmt, err error) { - crc := crc32.ChecksumIEEE([]byte(sqlStr)) - // TODO try hash(sqlStr+len(sqlStr)) - var has bool - stmt, has = session.stmtCache[crc] - if !has { - stmt, err = db.PrepareContext(session.ctx, sqlStr) - if err != nil { - return nil, err - } - session.stmtCache[crc] = stmt - } - return -} - -func (session *Session) getField(dataStruct *reflect.Value, key string, table *core.Table, idx int) (*reflect.Value, error) { - var col *core.Column - if col = table.GetColumnIdx(key, idx); col == nil { - return nil, ErrFieldIsNotExist{key, table.Name} - } - - fieldValue, err := col.ValueOfV(dataStruct) - if err != nil { - return nil, err - } - - if !fieldValue.IsValid() || !fieldValue.CanSet() { - return nil, ErrFieldIsNotValid{key, table.Name} - } - - return fieldValue, nil -} - -// Cell cell is a result of one column field -type Cell *interface{} - -func (session *Session) rows2Beans(rows *core.Rows, fields []string, - table *core.Table, newElemFunc func([]string) reflect.Value, - sliceValueSetFunc func(*reflect.Value, core.PK) error) error { - for rows.Next() { - var newValue = newElemFunc(fields) - bean := newValue.Interface() - dataStruct := newValue.Elem() - - // handle beforeClosures - scanResults, err := session.row2Slice(rows, fields, bean) - if err != nil { - return err - } - pk, err := session.slice2Bean(scanResults, fields, bean, &dataStruct, table) - if err != nil { - return err - } - session.afterProcessors = append(session.afterProcessors, executedProcessor{ - fun: func(*Session, interface{}) error { - return sliceValueSetFunc(&newValue, pk) - }, - session: session, - bean: bean, - }) - } - return nil -} - -func (session *Session) row2Slice(rows *core.Rows, fields []string, bean interface{}) ([]interface{}, error) { - for _, closure := range session.beforeClosures { - closure(bean) - } - - scanResults := make([]interface{}, len(fields)) - for i := 0; i < len(fields); i++ { - var cell interface{} - scanResults[i] = &cell - } - if err := rows.Scan(scanResults...); err != nil { - return nil, err - } - - if b, hasBeforeSet := bean.(BeforeSetProcessor); hasBeforeSet { - for ii, key := range fields { - b.BeforeSet(key, Cell(scanResults[ii].(*interface{}))) - } - } - return scanResults, nil -} - -func (session *Session) slice2Bean(scanResults []interface{}, fields []string, bean interface{}, dataStruct *reflect.Value, table *core.Table) (core.PK, error) { - defer func() { - if b, hasAfterSet := bean.(AfterSetProcessor); hasAfterSet { - for ii, key := range fields { - b.AfterSet(key, Cell(scanResults[ii].(*interface{}))) - } - } - }() - - // handle afterClosures - for _, closure := range session.afterClosures { - session.afterProcessors = append(session.afterProcessors, executedProcessor{ - fun: func(sess *Session, bean interface{}) error { - closure(bean) - return nil - }, - session: session, - bean: bean, - }) - } - - if a, has := bean.(AfterLoadProcessor); has { - session.afterProcessors = append(session.afterProcessors, executedProcessor{ - fun: func(sess *Session, bean interface{}) error { - a.AfterLoad() - return nil - }, - session: session, - bean: bean, - }) - } - - if a, has := bean.(AfterLoadSessionProcessor); has { - session.afterProcessors = append(session.afterProcessors, executedProcessor{ - fun: func(sess *Session, bean interface{}) error { - a.AfterLoad(sess) - return nil - }, - session: session, - bean: bean, - }) - } - - var tempMap = make(map[string]int) - var pk core.PK - for ii, key := range fields { - var idx int - var ok bool - var lKey = strings.ToLower(key) - if idx, ok = tempMap[lKey]; !ok { - idx = 0 - } else { - idx = idx + 1 - } - tempMap[lKey] = idx - - fieldValue, err := session.getField(dataStruct, key, table, idx) - if err != nil { - if !strings.Contains(err.Error(), "is not valid") { - session.engine.logger.Warn(err) - } - continue - } - if fieldValue == nil { - continue - } - rawValue := reflect.Indirect(reflect.ValueOf(scanResults[ii])) - - // if row is null then ignore - if rawValue.Interface() == nil { - continue - } - - if fieldValue.CanAddr() { - if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { - if data, err := value2Bytes(&rawValue); err == nil { - if err := structConvert.FromDB(data); err != nil { - return nil, err - } - } else { - return nil, err - } - continue - } - } - - if _, ok := fieldValue.Interface().(core.Conversion); ok { - if data, err := value2Bytes(&rawValue); err == nil { - if fieldValue.Kind() == reflect.Ptr && fieldValue.IsNil() { - fieldValue.Set(reflect.New(fieldValue.Type().Elem())) - } - fieldValue.Interface().(core.Conversion).FromDB(data) - } else { - return nil, err - } - continue - } - - rawValueType := reflect.TypeOf(rawValue.Interface()) - vv := reflect.ValueOf(rawValue.Interface()) - col := table.GetColumnIdx(key, idx) - if col.IsPrimaryKey { - pk = append(pk, rawValue.Interface()) - } - fieldType := fieldValue.Type() - hasAssigned := false - - if col.SQLType.IsJson() { - var bs []byte - if rawValueType.Kind() == reflect.String { - bs = []byte(vv.String()) - } else if rawValueType.ConvertibleTo(core.BytesType) { - bs = vv.Bytes() - } else { - return nil, fmt.Errorf("unsupported database data type: %s %v", key, rawValueType.Kind()) - } - - hasAssigned = true - - if len(bs) > 0 { - if fieldType.Kind() == reflect.String { - fieldValue.SetString(string(bs)) - continue - } - if fieldValue.CanAddr() { - err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface()) - if err != nil { - return nil, err - } - } else { - x := reflect.New(fieldType) - err := DefaultJSONHandler.Unmarshal(bs, x.Interface()) - if err != nil { - return nil, err - } - fieldValue.Set(x.Elem()) - } - } - - continue - } - - switch fieldType.Kind() { - case reflect.Complex64, reflect.Complex128: - // TODO: reimplement this - var bs []byte - if rawValueType.Kind() == reflect.String { - bs = []byte(vv.String()) - } else if rawValueType.ConvertibleTo(core.BytesType) { - bs = vv.Bytes() - } - - hasAssigned = true - if len(bs) > 0 { - if fieldValue.CanAddr() { - err := DefaultJSONHandler.Unmarshal(bs, fieldValue.Addr().Interface()) - if err != nil { - return nil, err - } - } else { - x := reflect.New(fieldType) - err := DefaultJSONHandler.Unmarshal(bs, x.Interface()) - if err != nil { - return nil, err - } - fieldValue.Set(x.Elem()) - } - } - case reflect.Slice, reflect.Array: - switch rawValueType.Kind() { - case reflect.Slice, reflect.Array: - switch rawValueType.Elem().Kind() { - case reflect.Uint8: - if fieldType.Elem().Kind() == reflect.Uint8 { - hasAssigned = true - if col.SQLType.IsText() { - x := reflect.New(fieldType) - err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface()) - if err != nil { - return nil, err - } - fieldValue.Set(x.Elem()) - } else { - if fieldValue.Len() > 0 { - for i := 0; i < fieldValue.Len(); i++ { - if i < vv.Len() { - fieldValue.Index(i).Set(vv.Index(i)) - } - } - } else { - for i := 0; i < vv.Len(); i++ { - fieldValue.Set(reflect.Append(*fieldValue, vv.Index(i))) - } - } - } - } - } - } - case reflect.String: - if rawValueType.Kind() == reflect.String { - hasAssigned = true - fieldValue.SetString(vv.String()) - } - case reflect.Bool: - if rawValueType.Kind() == reflect.Bool { - hasAssigned = true - fieldValue.SetBool(vv.Bool()) - } - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - switch rawValueType.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - hasAssigned = true - fieldValue.SetInt(vv.Int()) - } - case reflect.Float32, reflect.Float64: - switch rawValueType.Kind() { - case reflect.Float32, reflect.Float64: - hasAssigned = true - fieldValue.SetFloat(vv.Float()) - } - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - switch rawValueType.Kind() { - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - hasAssigned = true - fieldValue.SetUint(vv.Uint()) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - hasAssigned = true - fieldValue.SetUint(uint64(vv.Int())) - } - case reflect.Struct: - if fieldType.ConvertibleTo(core.TimeType) { - dbTZ := session.engine.DatabaseTZ - if col.TimeZone != nil { - dbTZ = col.TimeZone - } - - if rawValueType == core.TimeType { - hasAssigned = true - - t := vv.Convert(core.TimeType).Interface().(time.Time) - - z, _ := t.Zone() - // set new location if database don't save timezone or give an incorrect timezone - if len(z) == 0 || t.Year() == 0 || t.Location().String() != dbTZ.String() { // !nashtsai! HACK tmp work around for lib/pq doesn't properly time with location - session.engine.logger.Debugf("empty zone key[%v] : %v | zone: %v | location: %+v\n", key, t, z, *t.Location()) - t = time.Date(t.Year(), t.Month(), t.Day(), t.Hour(), - t.Minute(), t.Second(), t.Nanosecond(), dbTZ) - } - - t = t.In(session.engine.TZLocation) - fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) - } else if rawValueType == core.IntType || rawValueType == core.Int64Type || - rawValueType == core.Int32Type { - hasAssigned = true - - t := time.Unix(vv.Int(), 0).In(session.engine.TZLocation) - fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) - } else { - if d, ok := vv.Interface().([]uint8); ok { - hasAssigned = true - t, err := session.byte2Time(col, d) - if err != nil { - session.engine.logger.Error("byte2Time error:", err.Error()) - hasAssigned = false - } else { - fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) - } - } else if d, ok := vv.Interface().(string); ok { - hasAssigned = true - t, err := session.str2Time(col, d) - if err != nil { - session.engine.logger.Error("byte2Time error:", err.Error()) - hasAssigned = false - } else { - fieldValue.Set(reflect.ValueOf(t).Convert(fieldType)) - } - } else { - return nil, fmt.Errorf("rawValueType is %v, value is %v", rawValueType, vv.Interface()) - } - } - } else if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok { - // !! 增加支持sql.Scanner接口的结构,如sql.NullString - hasAssigned = true - if err := nulVal.Scan(vv.Interface()); err != nil { - session.engine.logger.Error("sql.Sanner error:", err.Error()) - hasAssigned = false - } - } else if col.SQLType.IsJson() { - if rawValueType.Kind() == reflect.String { - hasAssigned = true - x := reflect.New(fieldType) - if len([]byte(vv.String())) > 0 { - err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), x.Interface()) - if err != nil { - return nil, err - } - fieldValue.Set(x.Elem()) - } - } else if rawValueType.Kind() == reflect.Slice { - hasAssigned = true - x := reflect.New(fieldType) - if len(vv.Bytes()) > 0 { - err := DefaultJSONHandler.Unmarshal(vv.Bytes(), x.Interface()) - if err != nil { - return nil, err - } - fieldValue.Set(x.Elem()) - } - } - } else if session.statement.UseCascade { - table, err := session.engine.autoMapType(*fieldValue) - if err != nil { - return nil, err - } - - hasAssigned = true - if len(table.PrimaryKeys) != 1 { - return nil, errors.New("unsupported non or composited primary key cascade") - } - var pk = make(core.PK, len(table.PrimaryKeys)) - pk[0], err = asKind(vv, rawValueType) - if err != nil { - return nil, err - } - - if !isPKZero(pk) { - // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch - // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne - // property to be fetched lazily - structInter := reflect.New(fieldValue.Type()) - has, err := session.ID(pk).NoCascade().get(structInter.Interface()) - if err != nil { - return nil, err - } - if has { - fieldValue.Set(structInter.Elem()) - } else { - return nil, errors.New("cascade obj is not exist") - } - } - } - case reflect.Ptr: - // !nashtsai! TODO merge duplicated codes above - switch fieldType { - // following types case matching ptr's native type, therefore assign ptr directly - case core.PtrStringType: - if rawValueType.Kind() == reflect.String { - x := vv.String() - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrBoolType: - if rawValueType.Kind() == reflect.Bool { - x := vv.Bool() - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrTimeType: - if rawValueType == core.PtrTimeType { - hasAssigned = true - var x = rawValue.Interface().(time.Time) - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrFloat64Type: - if rawValueType.Kind() == reflect.Float64 { - x := vv.Float() - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrUint64Type: - if rawValueType.Kind() == reflect.Int64 { - var x = uint64(vv.Int()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrInt64Type: - if rawValueType.Kind() == reflect.Int64 { - x := vv.Int() - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrFloat32Type: - if rawValueType.Kind() == reflect.Float64 { - var x = float32(vv.Float()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrIntType: - if rawValueType.Kind() == reflect.Int64 { - var x = int(vv.Int()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrInt32Type: - if rawValueType.Kind() == reflect.Int64 { - var x = int32(vv.Int()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrInt8Type: - if rawValueType.Kind() == reflect.Int64 { - var x = int8(vv.Int()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrInt16Type: - if rawValueType.Kind() == reflect.Int64 { - var x = int16(vv.Int()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrUintType: - if rawValueType.Kind() == reflect.Int64 { - var x = uint(vv.Int()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.PtrUint32Type: - if rawValueType.Kind() == reflect.Int64 { - var x = uint32(vv.Int()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.Uint8Type: - if rawValueType.Kind() == reflect.Int64 { - var x = uint8(vv.Int()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.Uint16Type: - if rawValueType.Kind() == reflect.Int64 { - var x = uint16(vv.Int()) - hasAssigned = true - fieldValue.Set(reflect.ValueOf(&x)) - } - case core.Complex64Type: - var x complex64 - if len([]byte(vv.String())) > 0 { - err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x) - if err != nil { - return nil, err - } - fieldValue.Set(reflect.ValueOf(&x)) - } - hasAssigned = true - case core.Complex128Type: - var x complex128 - if len([]byte(vv.String())) > 0 { - err := DefaultJSONHandler.Unmarshal([]byte(vv.String()), &x) - if err != nil { - return nil, err - } - fieldValue.Set(reflect.ValueOf(&x)) - } - hasAssigned = true - } // switch fieldType - } // switch fieldType.Kind() - - // !nashtsai! for value can't be assigned directly fallback to convert to []byte then back to value - if !hasAssigned { - data, err := value2Bytes(&rawValue) - if err != nil { - return nil, err - } - - if err = session.bytes2Value(col, fieldValue, data); err != nil { - return nil, err - } - } - } - return pk, nil -} - -// saveLastSQL stores executed query information -func (session *Session) saveLastSQL(sql string, args ...interface{}) { - session.lastSQL = sql - session.lastSQLArgs = args - session.engine.logSQL(sql, args...) -} - -// LastSQL returns last query information -func (session *Session) LastSQL() (string, []interface{}) { - return session.lastSQL, session.lastSQLArgs -} - -// Unscoped always disable struct tag "deleted" -func (session *Session) Unscoped() *Session { - session.statement.Unscoped() - return session -} - -func (session *Session) incrVersionFieldValue(fieldValue *reflect.Value) { - switch fieldValue.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - fieldValue.SetInt(fieldValue.Int() + 1) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - fieldValue.SetUint(fieldValue.Uint() + 1) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_cols.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_cols.go deleted file mode 100644 index 1558074f3..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_cols.go +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "reflect" - "strings" - "time" - - "xorm.io/core" -) - -func setColumnInt(bean interface{}, col *core.Column, t int64) { - v, err := col.ValueOf(bean) - if err != nil { - return - } - if v.CanSet() { - switch v.Type().Kind() { - case reflect.Int, reflect.Int64, reflect.Int32: - v.SetInt(t) - case reflect.Uint, reflect.Uint64, reflect.Uint32: - v.SetUint(uint64(t)) - } - } -} - -func setColumnTime(bean interface{}, col *core.Column, t time.Time) { - v, err := col.ValueOf(bean) - if err != nil { - return - } - if v.CanSet() { - switch v.Type().Kind() { - case reflect.Struct: - v.Set(reflect.ValueOf(t).Convert(v.Type())) - case reflect.Int, reflect.Int64, reflect.Int32: - v.SetInt(t.Unix()) - case reflect.Uint, reflect.Uint64, reflect.Uint32: - v.SetUint(uint64(t.Unix())) - } - } -} - -func getFlagForColumn(m map[string]bool, col *core.Column) (val bool, has bool) { - if len(m) == 0 { - return false, false - } - - n := len(col.Name) - - for mk := range m { - if len(mk) != n { - continue - } - if strings.EqualFold(mk, col.Name) { - return m[mk], true - } - } - - return false, false -} - -func col2NewCols(columns ...string) []string { - newColumns := make([]string, 0, len(columns)) - for _, col := range columns { - col = strings.Replace(col, "`", "", -1) - col = strings.Replace(col, `"`, "", -1) - ccols := strings.Split(col, ",") - for _, c := range ccols { - newColumns = append(newColumns, strings.TrimSpace(c)) - } - } - return newColumns -} - -// Incr provides a query string like "count = count + 1" -func (session *Session) Incr(column string, arg ...interface{}) *Session { - session.statement.Incr(column, arg...) - return session -} - -// Decr provides a query string like "count = count - 1" -func (session *Session) Decr(column string, arg ...interface{}) *Session { - session.statement.Decr(column, arg...) - return session -} - -// SetExpr provides a query string like "column = {expression}" -func (session *Session) SetExpr(column string, expression interface{}) *Session { - session.statement.SetExpr(column, expression) - return session -} - -// Select provides some columns to special -func (session *Session) Select(str string) *Session { - session.statement.Select(str) - return session -} - -// Cols provides some columns to special -func (session *Session) Cols(columns ...string) *Session { - session.statement.Cols(columns...) - return session -} - -// AllCols ask all columns -func (session *Session) AllCols() *Session { - session.statement.AllCols() - return session -} - -// MustCols specify some columns must use even if they are empty -func (session *Session) MustCols(columns ...string) *Session { - session.statement.MustCols(columns...) - return session -} - -// UseBool automatically retrieve condition according struct, but -// if struct has bool field, it will ignore them. So use UseBool -// to tell system to do not ignore them. -// If no parameters, it will use all the bool field of struct, or -// it will use parameters's columns -func (session *Session) UseBool(columns ...string) *Session { - session.statement.UseBool(columns...) - return session -} - -// Distinct use for distinct columns. Caution: when you are using cache, -// distinct will not be cached because cache system need id, -// but distinct will not provide id -func (session *Session) Distinct(columns ...string) *Session { - session.statement.Distinct(columns...) - return session -} - -// Omit Only not use the parameters as select or update columns -func (session *Session) Omit(columns ...string) *Session { - session.statement.Omit(columns...) - return session -} - -// Nullable Set null when column is zero-value and nullable for update -func (session *Session) Nullable(columns ...string) *Session { - session.statement.Nullable(columns...) - return session -} - -// NoAutoTime means do not automatically give created field and updated field -// the current time on the current session temporarily -func (session *Session) NoAutoTime() *Session { - session.statement.UseAutoTime = false - return session -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_cond.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_cond.go deleted file mode 100644 index b16bdea8e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_cond.go +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import "xorm.io/builder" - -// Sql provides raw sql input parameter. When you have a complex SQL statement -// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. -// -// Deprecated: use SQL instead. -func (session *Session) Sql(query string, args ...interface{}) *Session { - return session.SQL(query, args...) -} - -// SQL provides raw sql input parameter. When you have a complex SQL statement -// and cannot use Where, Id, In and etc. Methods to describe, you can use SQL. -func (session *Session) SQL(query interface{}, args ...interface{}) *Session { - session.statement.SQL(query, args...) - return session -} - -// Where provides custom query condition. -func (session *Session) Where(query interface{}, args ...interface{}) *Session { - session.statement.Where(query, args...) - return session -} - -// And provides custom query condition. -func (session *Session) And(query interface{}, args ...interface{}) *Session { - session.statement.And(query, args...) - return session -} - -// Or provides custom query condition. -func (session *Session) Or(query interface{}, args ...interface{}) *Session { - session.statement.Or(query, args...) - return session -} - -// Id provides converting id as a query condition -// -// Deprecated: use ID instead -func (session *Session) Id(id interface{}) *Session { - return session.ID(id) -} - -// ID provides converting id as a query condition -func (session *Session) ID(id interface{}) *Session { - session.statement.ID(id) - return session -} - -// In provides a query string like "id in (1, 2, 3)" -func (session *Session) In(column string, args ...interface{}) *Session { - session.statement.In(column, args...) - return session -} - -// NotIn provides a query string like "id in (1, 2, 3)" -func (session *Session) NotIn(column string, args ...interface{}) *Session { - session.statement.NotIn(column, args...) - return session -} - -// Conds returns session query conditions except auto bean conditions -func (session *Session) Conds() builder.Cond { - return session.statement.cond -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_context.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_context.go deleted file mode 100644 index 915f05685..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_context.go +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2019 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import "context" - -// Context sets the context on this session -func (session *Session) Context(ctx context.Context) *Session { - session.ctx = ctx - return session -} - -// PingContext test if database is ok -func (session *Session) PingContext(ctx context.Context) error { - if session.isAutoClose { - defer session.Close() - } - - session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName()) - return session.DB().PingContext(ctx) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_convert.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_convert.go deleted file mode 100644 index 7f11354d5..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_convert.go +++ /dev/null @@ -1,671 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "database/sql/driver" - "errors" - "fmt" - "reflect" - "strconv" - "strings" - "time" - - "xorm.io/core" -) - -func (session *Session) str2Time(col *core.Column, data string) (outTime time.Time, outErr error) { - sdata := strings.TrimSpace(data) - var x time.Time - var err error - - var parseLoc = session.engine.DatabaseTZ - if col.TimeZone != nil { - parseLoc = col.TimeZone - } - - if sdata == zeroTime0 || sdata == zeroTime1 { - } else if !strings.ContainsAny(sdata, "- :") { // !nashtsai! has only found that mymysql driver is using this for time type column - // time stamp - sd, err := strconv.ParseInt(sdata, 10, 64) - if err == nil { - x = time.Unix(sd, 0) - //session.engine.logger.Debugf("time(0) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } else { - //session.engine.logger.Debugf("time(0) err key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } - } else if len(sdata) > 19 && strings.Contains(sdata, "-") { - x, err = time.ParseInLocation(time.RFC3339Nano, sdata, parseLoc) - session.engine.logger.Debugf("time(1) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - if err != nil { - x, err = time.ParseInLocation("2006-01-02 15:04:05.999999999", sdata, parseLoc) - //session.engine.logger.Debugf("time(2) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } - if err != nil { - x, err = time.ParseInLocation("2006-01-02 15:04:05.9999999 Z07:00", sdata, parseLoc) - //session.engine.logger.Debugf("time(3) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } - } else if len(sdata) == 19 && strings.Contains(sdata, "-") { - x, err = time.ParseInLocation("2006-01-02 15:04:05", sdata, parseLoc) - //session.engine.logger.Debugf("time(4) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } else if len(sdata) == 10 && sdata[4] == '-' && sdata[7] == '-' { - x, err = time.ParseInLocation("2006-01-02", sdata, parseLoc) - //session.engine.logger.Debugf("time(5) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } else if col.SQLType.Name == core.Time { - if strings.Contains(sdata, " ") { - ssd := strings.Split(sdata, " ") - sdata = ssd[1] - } - - sdata = strings.TrimSpace(sdata) - if session.engine.dialect.DBType() == core.MYSQL && len(sdata) > 8 { - sdata = sdata[len(sdata)-8:] - } - - st := fmt.Sprintf("2006-01-02 %v", sdata) - x, err = time.ParseInLocation("2006-01-02 15:04:05", st, parseLoc) - //session.engine.logger.Debugf("time(6) key[%v]: %+v | sdata: [%v]\n", col.FieldName, x, sdata) - } else { - outErr = fmt.Errorf("unsupported time format %v", sdata) - return - } - if err != nil { - outErr = fmt.Errorf("unsupported time format %v: %v", sdata, err) - return - } - outTime = x.In(session.engine.TZLocation) - return -} - -func (session *Session) byte2Time(col *core.Column, data []byte) (outTime time.Time, outErr error) { - return session.str2Time(col, string(data)) -} - -var ( - nullFloatType = reflect.TypeOf(sql.NullFloat64{}) -) - -// convert a db data([]byte) to a field value -func (session *Session) bytes2Value(col *core.Column, fieldValue *reflect.Value, data []byte) error { - if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { - return structConvert.FromDB(data) - } - - if structConvert, ok := fieldValue.Interface().(core.Conversion); ok { - return structConvert.FromDB(data) - } - - var v interface{} - key := col.Name - fieldType := fieldValue.Type() - - switch fieldType.Kind() { - case reflect.Complex64, reflect.Complex128: - x := reflect.New(fieldType) - if len(data) > 0 { - err := DefaultJSONHandler.Unmarshal(data, x.Interface()) - if err != nil { - session.engine.logger.Error(err) - return err - } - fieldValue.Set(x.Elem()) - } - case reflect.Slice, reflect.Array, reflect.Map: - v = data - t := fieldType.Elem() - k := t.Kind() - if col.SQLType.IsText() { - x := reflect.New(fieldType) - if len(data) > 0 { - err := DefaultJSONHandler.Unmarshal(data, x.Interface()) - if err != nil { - session.engine.logger.Error(err) - return err - } - fieldValue.Set(x.Elem()) - } - } else if col.SQLType.IsBlob() { - if k == reflect.Uint8 { - fieldValue.Set(reflect.ValueOf(v)) - } else { - x := reflect.New(fieldType) - if len(data) > 0 { - err := DefaultJSONHandler.Unmarshal(data, x.Interface()) - if err != nil { - session.engine.logger.Error(err) - return err - } - fieldValue.Set(x.Elem()) - } - } - } else { - return ErrUnSupportedType - } - case reflect.String: - fieldValue.SetString(string(data)) - case reflect.Bool: - v, err := asBool(data) - if err != nil { - return fmt.Errorf("arg %v as bool: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(v)) - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - sdata := string(data) - var x int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - session.engine.dialect.DBType() == core.MYSQL { // !nashtsai! TODO dialect needs to provide conversion interface API - if len(data) == 1 { - x = int64(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x, err = strconv.ParseInt(sdata, 16, 64) - } else if strings.HasPrefix(sdata, "0") { - x, err = strconv.ParseInt(sdata, 8, 64) - } else if strings.EqualFold(sdata, "true") { - x = 1 - } else if strings.EqualFold(sdata, "false") { - x = 0 - } else { - x, err = strconv.ParseInt(sdata, 10, 64) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.SetInt(x) - case reflect.Float32, reflect.Float64: - x, err := strconv.ParseFloat(string(data), 64) - if err != nil { - return fmt.Errorf("arg %v as float64: %s", key, err.Error()) - } - fieldValue.SetFloat(x) - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - x, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.SetUint(x) - //Currently only support Time type - case reflect.Struct: - // !! 增加支持sql.Scanner接口的结构,如sql.NullString - if nulVal, ok := fieldValue.Addr().Interface().(sql.Scanner); ok { - if err := nulVal.Scan(data); err != nil { - return fmt.Errorf("sql.Scan(%v) failed: %s ", data, err.Error()) - } - } else { - if fieldType.ConvertibleTo(core.TimeType) { - x, err := session.byte2Time(col, data) - if err != nil { - return err - } - v = x - fieldValue.Set(reflect.ValueOf(v).Convert(fieldType)) - } else if session.statement.UseCascade { - table, err := session.engine.autoMapType(*fieldValue) - if err != nil { - return err - } - - // TODO: current only support 1 primary key - if len(table.PrimaryKeys) > 1 { - return errors.New("unsupported composited primary key cascade") - } - - var pk = make(core.PK, len(table.PrimaryKeys)) - rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) - pk[0], err = str2PK(string(data), rawValueType) - if err != nil { - return err - } - - if !isPKZero(pk) { - // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch - // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne - // property to be fetched lazily - structInter := reflect.New(fieldValue.Type()) - has, err := session.ID(pk).NoCascade().get(structInter.Interface()) - if err != nil { - return err - } - if has { - v = structInter.Elem().Interface() - fieldValue.Set(reflect.ValueOf(v)) - } else { - return errors.New("cascade obj is not exist") - } - } - } - } - case reflect.Ptr: - // !nashtsai! TODO merge duplicated codes above - //typeStr := fieldType.String() - switch fieldType.Elem().Kind() { - // case "*string": - case core.StringType.Kind(): - x := string(data) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*bool": - case core.BoolType.Kind(): - d := string(data) - v, err := strconv.ParseBool(d) - if err != nil { - return fmt.Errorf("arg %v as bool: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&v).Convert(fieldType)) - // case "*complex64": - case core.Complex64Type.Kind(): - var x complex64 - if len(data) > 0 { - err := DefaultJSONHandler.Unmarshal(data, &x) - if err != nil { - session.engine.logger.Error(err) - return err - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - } - // case "*complex128": - case core.Complex128Type.Kind(): - var x complex128 - if len(data) > 0 { - err := DefaultJSONHandler.Unmarshal(data, &x) - if err != nil { - session.engine.logger.Error(err) - return err - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - } - // case "*float64": - case core.Float64Type.Kind(): - x, err := strconv.ParseFloat(string(data), 64) - if err != nil { - return fmt.Errorf("arg %v as float64: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*float32": - case core.Float32Type.Kind(): - var x float32 - x1, err := strconv.ParseFloat(string(data), 32) - if err != nil { - return fmt.Errorf("arg %v as float32: %s", key, err.Error()) - } - x = float32(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint64": - case core.Uint64Type.Kind(): - var x uint64 - x, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint": - case core.UintType.Kind(): - var x uint - x1, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - x = uint(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint32": - case core.Uint32Type.Kind(): - var x uint32 - x1, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - x = uint32(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint8": - case core.Uint8Type.Kind(): - var x uint8 - x1, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - x = uint8(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*uint16": - case core.Uint16Type.Kind(): - var x uint16 - x1, err := strconv.ParseUint(string(data), 10, 64) - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - x = uint16(x1) - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int64": - case core.Int64Type.Kind(): - sdata := string(data) - var x int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - strings.Contains(session.engine.DriverName(), "mysql") { - if len(data) == 1 { - x = int64(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x, err = strconv.ParseInt(sdata, 16, 64) - } else if strings.HasPrefix(sdata, "0") { - x, err = strconv.ParseInt(sdata, 8, 64) - } else { - x, err = strconv.ParseInt(sdata, 10, 64) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int": - case core.IntType.Kind(): - sdata := string(data) - var x int - var x1 int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - strings.Contains(session.engine.DriverName(), "mysql") { - if len(data) == 1 { - x = int(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x1, err = strconv.ParseInt(sdata, 16, 64) - x = int(x1) - } else if strings.HasPrefix(sdata, "0") { - x1, err = strconv.ParseInt(sdata, 8, 64) - x = int(x1) - } else { - x1, err = strconv.ParseInt(sdata, 10, 64) - x = int(x1) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int32": - case core.Int32Type.Kind(): - sdata := string(data) - var x int32 - var x1 int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - session.engine.dialect.DBType() == core.MYSQL { - if len(data) == 1 { - x = int32(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x1, err = strconv.ParseInt(sdata, 16, 64) - x = int32(x1) - } else if strings.HasPrefix(sdata, "0") { - x1, err = strconv.ParseInt(sdata, 8, 64) - x = int32(x1) - } else { - x1, err = strconv.ParseInt(sdata, 10, 64) - x = int32(x1) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int8": - case core.Int8Type.Kind(): - sdata := string(data) - var x int8 - var x1 int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - strings.Contains(session.engine.DriverName(), "mysql") { - if len(data) == 1 { - x = int8(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x1, err = strconv.ParseInt(sdata, 16, 64) - x = int8(x1) - } else if strings.HasPrefix(sdata, "0") { - x1, err = strconv.ParseInt(sdata, 8, 64) - x = int8(x1) - } else { - x1, err = strconv.ParseInt(sdata, 10, 64) - x = int8(x1) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*int16": - case core.Int16Type.Kind(): - sdata := string(data) - var x int16 - var x1 int64 - var err error - // for mysql, when use bit, it returned \x01 - if col.SQLType.Name == core.Bit && - strings.Contains(session.engine.DriverName(), "mysql") { - if len(data) == 1 { - x = int16(data[0]) - } else { - x = 0 - } - } else if strings.HasPrefix(sdata, "0x") { - x1, err = strconv.ParseInt(sdata, 16, 64) - x = int16(x1) - } else if strings.HasPrefix(sdata, "0") { - x1, err = strconv.ParseInt(sdata, 8, 64) - x = int16(x1) - } else { - x1, err = strconv.ParseInt(sdata, 10, 64) - x = int16(x1) - } - if err != nil { - return fmt.Errorf("arg %v as int: %s", key, err.Error()) - } - fieldValue.Set(reflect.ValueOf(&x).Convert(fieldType)) - // case "*SomeStruct": - case reflect.Struct: - switch fieldType { - // case "*.time.Time": - case core.PtrTimeType: - x, err := session.byte2Time(col, data) - if err != nil { - return err - } - v = x - fieldValue.Set(reflect.ValueOf(&x)) - default: - if session.statement.UseCascade { - structInter := reflect.New(fieldType.Elem()) - table, err := session.engine.autoMapType(structInter.Elem()) - if err != nil { - return err - } - - if len(table.PrimaryKeys) > 1 { - return errors.New("unsupported composited primary key cascade") - } - - var pk = make(core.PK, len(table.PrimaryKeys)) - rawValueType := table.ColumnType(table.PKColumns()[0].FieldName) - pk[0], err = str2PK(string(data), rawValueType) - if err != nil { - return err - } - - if !isPKZero(pk) { - // !nashtsai! TODO for hasOne relationship, it's preferred to use join query for eager fetch - // however, also need to consider adding a 'lazy' attribute to xorm tag which allow hasOne - // property to be fetched lazily - has, err := session.ID(pk).NoCascade().get(structInter.Interface()) - if err != nil { - return err - } - if has { - v = structInter.Interface() - fieldValue.Set(reflect.ValueOf(v)) - } else { - return errors.New("cascade obj is not exist") - } - } - } else { - return fmt.Errorf("unsupported struct type in Scan: %s", fieldValue.Type().String()) - } - } - default: - return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) - } - default: - return fmt.Errorf("unsupported type in Scan: %s", fieldValue.Type().String()) - } - - return nil -} - -// convert a field value of a struct to interface for put into db -func (session *Session) value2Interface(col *core.Column, fieldValue reflect.Value) (interface{}, error) { - if fieldValue.CanAddr() { - if fieldConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { - data, err := fieldConvert.ToDB() - if err != nil { - return 0, err - } - if col.SQLType.IsBlob() { - return data, nil - } - return string(data), nil - } - } - - if fieldConvert, ok := fieldValue.Interface().(core.Conversion); ok { - data, err := fieldConvert.ToDB() - if err != nil { - return 0, err - } - if col.SQLType.IsBlob() { - return data, nil - } - return string(data), nil - } - - fieldType := fieldValue.Type() - k := fieldType.Kind() - if k == reflect.Ptr { - if fieldValue.IsNil() { - return nil, nil - } else if !fieldValue.IsValid() { - session.engine.logger.Warn("the field[", col.FieldName, "] is invalid") - return nil, nil - } else { - // !nashtsai! deference pointer type to instance type - fieldValue = fieldValue.Elem() - fieldType = fieldValue.Type() - k = fieldType.Kind() - } - } - - switch k { - case reflect.Bool: - return fieldValue.Bool(), nil - case reflect.String: - return fieldValue.String(), nil - case reflect.Struct: - if fieldType.ConvertibleTo(core.TimeType) { - t := fieldValue.Convert(core.TimeType).Interface().(time.Time) - tf := session.engine.formatColTime(col, t) - return tf, nil - } else if fieldType.ConvertibleTo(nullFloatType) { - t := fieldValue.Convert(nullFloatType).Interface().(sql.NullFloat64) - if !t.Valid { - return nil, nil - } - return t.Float64, nil - } - - if !col.SQLType.IsJson() { - // !! 增加支持driver.Valuer接口的结构,如sql.NullString - if v, ok := fieldValue.Interface().(driver.Valuer); ok { - return v.Value() - } - - fieldTable, err := session.engine.autoMapType(fieldValue) - if err != nil { - return nil, err - } - if len(fieldTable.PrimaryKeys) == 1 { - pkField := reflect.Indirect(fieldValue).FieldByName(fieldTable.PKColumns()[0].FieldName) - return pkField.Interface(), nil - } - return 0, fmt.Errorf("no primary key for col %v", col.Name) - } - - if col.SQLType.IsText() { - bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - session.engine.logger.Error(err) - return 0, err - } - return string(bytes), nil - } else if col.SQLType.IsBlob() { - bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - session.engine.logger.Error(err) - return 0, err - } - return bytes, nil - } - return nil, fmt.Errorf("Unsupported type %v", fieldValue.Type()) - case reflect.Complex64, reflect.Complex128: - bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - session.engine.logger.Error(err) - return 0, err - } - return string(bytes), nil - case reflect.Array, reflect.Slice, reflect.Map: - if !fieldValue.IsValid() { - return fieldValue.Interface(), nil - } - - if col.SQLType.IsText() { - bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - session.engine.logger.Error(err) - return 0, err - } - return string(bytes), nil - } else if col.SQLType.IsBlob() { - var bytes []byte - var err error - if (k == reflect.Slice) && - (fieldValue.Type().Elem().Kind() == reflect.Uint8) { - bytes = fieldValue.Bytes() - } else { - bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - session.engine.logger.Error(err) - return 0, err - } - } - return bytes, nil - } - return nil, ErrUnSupportedType - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uint: - return int64(fieldValue.Uint()), nil - default: - return fieldValue.Interface(), nil - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_delete.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_delete.go deleted file mode 100644 index 675d4d8c7..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_delete.go +++ /dev/null @@ -1,244 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "strconv" - - "xorm.io/core" -) - -func (session *Session) cacheDelete(table *core.Table, tableName, sqlStr string, args ...interface{}) error { - if table == nil || - session.tx != nil { - return ErrCacheFailed - } - - for _, filter := range session.engine.dialect.Filters() { - sqlStr = filter.Do(sqlStr, session.engine.dialect, table) - } - - newsql := session.statement.convertIDSQL(sqlStr) - if newsql == "" { - return ErrCacheFailed - } - - cacher := session.engine.getCacher(tableName) - pkColumns := table.PKColumns() - ids, err := core.GetCacheSql(cacher, tableName, newsql, args) - if err != nil { - resultsSlice, err := session.queryBytes(newsql, args...) - if err != nil { - return err - } - ids = make([]core.PK, 0) - if len(resultsSlice) > 0 { - for _, data := range resultsSlice { - var id int64 - var pk core.PK = make([]interface{}, 0) - for _, col := range pkColumns { - if v, ok := data[col.Name]; !ok { - return errors.New("no id") - } else if col.SQLType.IsText() { - pk = append(pk, string(v)) - } else if col.SQLType.IsNumeric() { - id, err = strconv.ParseInt(string(v), 10, 64) - if err != nil { - return err - } - pk = append(pk, id) - } else { - return errors.New("not supported primary key type") - } - } - ids = append(ids, pk) - } - } - } - - for _, id := range ids { - session.engine.logger.Debug("[cacheDelete] delete cache obj:", tableName, id) - sid, err := id.ToString() - if err != nil { - return err - } - cacher.DelBean(tableName, sid) - } - session.engine.logger.Debug("[cacheDelete] clear cache table:", tableName) - cacher.ClearIds(tableName) - return nil -} - -// Delete records, bean's non-empty fields are conditions -func (session *Session) Delete(bean interface{}) (int64, error) { - if session.isAutoClose { - defer session.Close() - } - - if session.statement.lastError != nil { - return 0, session.statement.lastError - } - - if err := session.statement.setRefBean(bean); err != nil { - return 0, err - } - - // handle before delete processors - for _, closure := range session.beforeClosures { - closure(bean) - } - cleanupProcessorsClosures(&session.beforeClosures) - - if processor, ok := interface{}(bean).(BeforeDeleteProcessor); ok { - processor.BeforeDelete() - } - - condSQL, condArgs, err := session.statement.genConds(bean) - if err != nil { - return 0, err - } - if len(condSQL) == 0 && session.statement.LimitN == 0 { - return 0, ErrNeedDeletedCond - } - - var tableNameNoQuote = session.statement.TableName() - var tableName = session.engine.Quote(tableNameNoQuote) - var table = session.statement.RefTable - var deleteSQL string - if len(condSQL) > 0 { - deleteSQL = fmt.Sprintf("DELETE FROM %v WHERE %v", tableName, condSQL) - } else { - deleteSQL = fmt.Sprintf("DELETE FROM %v", tableName) - } - - var orderSQL string - if len(session.statement.OrderStr) > 0 { - orderSQL += fmt.Sprintf(" ORDER BY %s", session.statement.OrderStr) - } - if session.statement.LimitN > 0 { - orderSQL += fmt.Sprintf(" LIMIT %d", session.statement.LimitN) - } - - if len(orderSQL) > 0 { - switch session.engine.dialect.DBType() { - case core.POSTGRES: - inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL) - if len(condSQL) > 0 { - deleteSQL += " AND " + inSQL - } else { - deleteSQL += " WHERE " + inSQL - } - case core.SQLITE: - inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL) - if len(condSQL) > 0 { - deleteSQL += " AND " + inSQL - } else { - deleteSQL += " WHERE " + inSQL - } - // TODO: how to handle delete limit on mssql? - case core.MSSQL: - return 0, ErrNotImplemented - default: - deleteSQL += orderSQL - } - } - - var realSQL string - argsForCache := make([]interface{}, 0, len(condArgs)*2) - if session.statement.unscoped || table.DeletedColumn() == nil { // tag "deleted" is disabled - realSQL = deleteSQL - copy(argsForCache, condArgs) - argsForCache = append(condArgs, argsForCache...) - } else { - // !oinume! sqlStrForCache and argsForCache is needed to behave as executing "DELETE FROM ..." for cache. - copy(argsForCache, condArgs) - argsForCache = append(condArgs, argsForCache...) - - deletedColumn := table.DeletedColumn() - realSQL = fmt.Sprintf("UPDATE %v SET %v = ? WHERE %v", - session.engine.Quote(session.statement.TableName()), - session.engine.Quote(deletedColumn.Name), - condSQL) - - if len(orderSQL) > 0 { - switch session.engine.dialect.DBType() { - case core.POSTGRES: - inSQL := fmt.Sprintf("ctid IN (SELECT ctid FROM %s%s)", tableName, orderSQL) - if len(condSQL) > 0 { - realSQL += " AND " + inSQL - } else { - realSQL += " WHERE " + inSQL - } - case core.SQLITE: - inSQL := fmt.Sprintf("rowid IN (SELECT rowid FROM %s%s)", tableName, orderSQL) - if len(condSQL) > 0 { - realSQL += " AND " + inSQL - } else { - realSQL += " WHERE " + inSQL - } - // TODO: how to handle delete limit on mssql? - case core.MSSQL: - return 0, ErrNotImplemented - default: - realSQL += orderSQL - } - } - - // !oinume! Insert nowTime to the head of session.statement.Params - condArgs = append(condArgs, "") - paramsLen := len(condArgs) - copy(condArgs[1:paramsLen], condArgs[0:paramsLen-1]) - - val, t := session.engine.nowTime(deletedColumn) - condArgs[0] = val - - var colName = deletedColumn.Name - session.afterClosures = append(session.afterClosures, func(bean interface{}) { - col := table.GetColumn(colName) - setColumnTime(bean, col, t) - }) - } - - if cacher := session.engine.getCacher(tableNameNoQuote); cacher != nil && session.statement.UseCache { - session.cacheDelete(table, tableNameNoQuote, deleteSQL, argsForCache...) - } - - session.statement.RefTable = table - res, err := session.exec(realSQL, condArgs...) - if err != nil { - return 0, err - } - - // handle after delete processors - if session.isAutoCommit { - for _, closure := range session.afterClosures { - closure(bean) - } - if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok { - processor.AfterDelete() - } - } else { - lenAfterClosures := len(session.afterClosures) - if lenAfterClosures > 0 { - if value, has := session.afterDeleteBeans[bean]; has && value != nil { - *value = append(*value, session.afterClosures...) - } else { - afterClosures := make([]func(interface{}), lenAfterClosures) - copy(afterClosures, session.afterClosures) - session.afterDeleteBeans[bean] = &afterClosures - } - } else { - if _, ok := interface{}(bean).(AfterDeleteProcessor); ok { - session.afterDeleteBeans[bean] = nil - } - } - } - cleanupProcessorsClosures(&session.afterClosures) - // -- - - return res.RowsAffected() -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_exist.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_exist.go deleted file mode 100644 index 660cc47e4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_exist.go +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "reflect" - - "xorm.io/builder" - "xorm.io/core" -) - -// Exist returns true if the record exist otherwise return false -func (session *Session) Exist(bean ...interface{}) (bool, error) { - if session.isAutoClose { - defer session.Close() - } - - if session.statement.lastError != nil { - return false, session.statement.lastError - } - - var sqlStr string - var args []interface{} - var err error - - if session.statement.RawSQL == "" { - if len(bean) == 0 { - tableName := session.statement.TableName() - if len(tableName) <= 0 { - return false, ErrTableNotFound - } - - tableName = session.statement.Engine.Quote(tableName) - - if session.statement.cond.IsValid() { - condSQL, condArgs, err := builder.ToSQL(session.statement.cond) - if err != nil { - return false, err - } - - if session.engine.dialect.DBType() == core.MSSQL { - sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s WHERE %s", tableName, condSQL) - } else if session.engine.dialect.DBType() == core.ORACLE { - sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE (%s) AND ROWNUM=1", tableName, condSQL) - } else { - sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE %s LIMIT 1", tableName, condSQL) - } - args = condArgs - } else { - if session.engine.dialect.DBType() == core.MSSQL { - sqlStr = fmt.Sprintf("SELECT TOP 1 * FROM %s", tableName) - } else if session.engine.dialect.DBType() == core.ORACLE { - sqlStr = fmt.Sprintf("SELECT * FROM %s WHERE ROWNUM=1", tableName) - } else { - sqlStr = fmt.Sprintf("SELECT * FROM %s LIMIT 1", tableName) - } - args = []interface{}{} - } - } else { - beanValue := reflect.ValueOf(bean[0]) - if beanValue.Kind() != reflect.Ptr { - return false, errors.New("needs a pointer") - } - - if beanValue.Elem().Kind() == reflect.Struct { - if err := session.statement.setRefBean(bean[0]); err != nil { - return false, err - } - } - - if len(session.statement.TableName()) <= 0 { - return false, ErrTableNotFound - } - session.statement.Limit(1) - sqlStr, args, err = session.statement.genGetSQL(bean[0]) - if err != nil { - return false, err - } - } - } else { - sqlStr = session.statement.RawSQL - args = session.statement.RawParams - } - - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return false, err - } - defer rows.Close() - - return rows.Next(), nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_find.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_find.go deleted file mode 100644 index 6b8aa469d..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_find.go +++ /dev/null @@ -1,505 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "reflect" - "strings" - - "xorm.io/builder" - "xorm.io/core" -) - -const ( - tpStruct = iota - tpNonStruct -) - -// Find retrieve records from table, condiBeans's non-empty fields -// are conditions. beans could be []Struct, []*Struct, map[int64]Struct -// map[int64]*Struct -func (session *Session) Find(rowsSlicePtr interface{}, condiBean ...interface{}) error { - if session.isAutoClose { - defer session.Close() - } - return session.find(rowsSlicePtr, condiBean...) -} - -// FindAndCount find the results and also return the counts -func (session *Session) FindAndCount(rowsSlicePtr interface{}, condiBean ...interface{}) (int64, error) { - if session.isAutoClose { - defer session.Close() - } - - session.autoResetStatement = false - err := session.find(rowsSlicePtr, condiBean...) - if err != nil { - return 0, err - } - - sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) - if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map { - return 0, errors.New("needs a pointer to a slice or a map") - } - - sliceElementType := sliceValue.Type().Elem() - if sliceElementType.Kind() == reflect.Ptr { - sliceElementType = sliceElementType.Elem() - } - session.autoResetStatement = true - - if session.statement.selectStr != "" { - session.statement.selectStr = "" - } - if session.statement.OrderStr != "" { - session.statement.OrderStr = "" - } - - return session.Count(reflect.New(sliceElementType).Interface()) -} - -func (session *Session) find(rowsSlicePtr interface{}, condiBean ...interface{}) error { - defer session.resetStatement() - - if session.statement.lastError != nil { - return session.statement.lastError - } - - sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) - if sliceValue.Kind() != reflect.Slice && sliceValue.Kind() != reflect.Map { - return errors.New("needs a pointer to a slice or a map") - } - - sliceElementType := sliceValue.Type().Elem() - - var tp = tpStruct - if session.statement.RefTable == nil { - if sliceElementType.Kind() == reflect.Ptr { - if sliceElementType.Elem().Kind() == reflect.Struct { - pv := reflect.New(sliceElementType.Elem()) - if err := session.statement.setRefValue(pv); err != nil { - return err - } - } else { - tp = tpNonStruct - } - } else if sliceElementType.Kind() == reflect.Struct { - pv := reflect.New(sliceElementType) - if err := session.statement.setRefValue(pv); err != nil { - return err - } - } else { - tp = tpNonStruct - } - } - - var table = session.statement.RefTable - - var addedTableName = (len(session.statement.JoinStr) > 0) - var autoCond builder.Cond - if tp == tpStruct { - if !session.statement.noAutoCondition && len(condiBean) > 0 { - var err error - autoCond, err = session.statement.buildConds(table, condiBean[0], true, true, false, true, addedTableName) - if err != nil { - return err - } - } else { - // !oinume! Add " IS NULL" to WHERE whatever condiBean is given. - // See https://github.com/go-xorm/xorm/issues/179 - if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled - var colName = session.engine.Quote(col.Name) - if addedTableName { - var nm = session.statement.TableName() - if len(session.statement.TableAlias) > 0 { - nm = session.statement.TableAlias - } - colName = session.engine.Quote(nm) + "." + colName - } - - autoCond = session.engine.CondDeleted(colName) - } - } - } - - var sqlStr string - var args []interface{} - var err error - if session.statement.RawSQL == "" { - if len(session.statement.TableName()) <= 0 { - return ErrTableNotFound - } - - var columnStr = session.statement.ColumnStr - if len(session.statement.selectStr) > 0 { - columnStr = session.statement.selectStr - } else { - if session.statement.JoinStr == "" { - if columnStr == "" { - if session.statement.GroupByStr != "" { - columnStr = session.engine.quoteColumns(session.statement.GroupByStr) - } else { - columnStr = session.statement.genColumnStr() - } - } - } else { - if columnStr == "" { - if session.statement.GroupByStr != "" { - columnStr = session.engine.quoteColumns(session.statement.GroupByStr) - } else { - columnStr = "*" - } - } - } - if columnStr == "" { - columnStr = "*" - } - } - - session.statement.cond = session.statement.cond.And(autoCond) - condSQL, condArgs, err := builder.ToSQL(session.statement.cond) - if err != nil { - return err - } - - args = append(session.statement.joinArgs, condArgs...) - sqlStr, err = session.statement.genSelectSQL(columnStr, condSQL, true, true) - if err != nil { - return err - } - // for mssql and use limit - qs := strings.Count(sqlStr, "?") - if len(args)*2 == qs { - args = append(args, args...) - } - } else { - sqlStr = session.statement.RawSQL - args = session.statement.RawParams - } - - if session.canCache() { - if cacher := session.engine.getCacher(session.statement.TableName()); cacher != nil && - !session.statement.IsDistinct && - !session.statement.unscoped { - err = session.cacheFind(sliceElementType, sqlStr, rowsSlicePtr, args...) - if err != ErrCacheFailed { - return err - } - err = nil // !nashtsai! reset err to nil for ErrCacheFailed - session.engine.logger.Warn("Cache Find Failed") - } - } - - return session.noCacheFind(table, sliceValue, sqlStr, args...) -} - -func (session *Session) noCacheFind(table *core.Table, containerValue reflect.Value, sqlStr string, args ...interface{}) error { - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return err - } - defer rows.Close() - - fields, err := rows.Columns() - if err != nil { - return err - } - - var newElemFunc func(fields []string) reflect.Value - elemType := containerValue.Type().Elem() - var isPointer bool - if elemType.Kind() == reflect.Ptr { - isPointer = true - elemType = elemType.Elem() - } - if elemType.Kind() == reflect.Ptr { - return errors.New("pointer to pointer is not supported") - } - - newElemFunc = func(fields []string) reflect.Value { - switch elemType.Kind() { - case reflect.Slice: - slice := reflect.MakeSlice(elemType, len(fields), len(fields)) - x := reflect.New(slice.Type()) - x.Elem().Set(slice) - return x - case reflect.Map: - mp := reflect.MakeMap(elemType) - x := reflect.New(mp.Type()) - x.Elem().Set(mp) - return x - } - return reflect.New(elemType) - } - - var containerValueSetFunc func(*reflect.Value, core.PK) error - - if containerValue.Kind() == reflect.Slice { - containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error { - if isPointer { - containerValue.Set(reflect.Append(containerValue, newValue.Elem().Addr())) - } else { - containerValue.Set(reflect.Append(containerValue, newValue.Elem())) - } - return nil - } - } else { - keyType := containerValue.Type().Key() - if len(table.PrimaryKeys) == 0 { - return errors.New("don't support multiple primary key's map has non-slice key type") - } - if len(table.PrimaryKeys) > 1 && keyType.Kind() != reflect.Slice { - return errors.New("don't support multiple primary key's map has non-slice key type") - } - - containerValueSetFunc = func(newValue *reflect.Value, pk core.PK) error { - keyValue := reflect.New(keyType) - err := convertPKToValue(table, keyValue.Interface(), pk) - if err != nil { - return err - } - if isPointer { - containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem().Addr()) - } else { - containerValue.SetMapIndex(keyValue.Elem(), newValue.Elem()) - } - return nil - } - } - - if elemType.Kind() == reflect.Struct { - var newValue = newElemFunc(fields) - dataStruct := rValue(newValue.Interface()) - tb, err := session.engine.autoMapType(dataStruct) - if err != nil { - return err - } - err = session.rows2Beans(rows, fields, tb, newElemFunc, containerValueSetFunc) - rows.Close() - if err != nil { - return err - } - return session.executeProcessors() - } - - for rows.Next() { - var newValue = newElemFunc(fields) - bean := newValue.Interface() - - switch elemType.Kind() { - case reflect.Slice: - err = rows.ScanSlice(bean) - case reflect.Map: - err = rows.ScanMap(bean) - default: - err = rows.Scan(bean) - } - - if err != nil { - return err - } - - if err := containerValueSetFunc(&newValue, nil); err != nil { - return err - } - } - return nil -} - -func convertPKToValue(table *core.Table, dst interface{}, pk core.PK) error { - cols := table.PKColumns() - if len(cols) == 1 { - return convertAssign(dst, pk[0]) - } - - dst = pk - return nil -} - -func (session *Session) cacheFind(t reflect.Type, sqlStr string, rowsSlicePtr interface{}, args ...interface{}) (err error) { - if !session.canCache() || - indexNoCase(sqlStr, "having") != -1 || - indexNoCase(sqlStr, "group by") != -1 { - return ErrCacheFailed - } - - tableName := session.statement.TableName() - cacher := session.engine.getCacher(tableName) - if cacher == nil { - return nil - } - - for _, filter := range session.engine.dialect.Filters() { - sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable) - } - - newsql := session.statement.convertIDSQL(sqlStr) - if newsql == "" { - return ErrCacheFailed - } - - table := session.statement.RefTable - ids, err := core.GetCacheSql(cacher, tableName, newsql, args) - if err != nil { - rows, err := session.queryRows(newsql, args...) - if err != nil { - return err - } - defer rows.Close() - - var i int - ids = make([]core.PK, 0) - for rows.Next() { - i++ - if i > 500 { - session.engine.logger.Debug("[cacheFind] ids length > 500, no cache") - return ErrCacheFailed - } - var res = make([]string, len(table.PrimaryKeys)) - err = rows.ScanSlice(&res) - if err != nil { - return err - } - var pk core.PK = make([]interface{}, len(table.PrimaryKeys)) - for i, col := range table.PKColumns() { - pk[i], err = session.engine.idTypeAssertion(col, res[i]) - if err != nil { - return err - } - } - - ids = append(ids, pk) - } - - session.engine.logger.Debug("[cacheFind] cache sql:", ids, tableName, sqlStr, newsql, args) - err = core.PutCacheSql(cacher, ids, tableName, newsql, args) - if err != nil { - return err - } - } else { - session.engine.logger.Debug("[cacheFind] cache hit sql:", tableName, sqlStr, newsql, args) - } - - sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) - - ididxes := make(map[string]int) - var ides []core.PK - var temps = make([]interface{}, len(ids)) - - for idx, id := range ids { - sid, err := id.ToString() - if err != nil { - return err - } - bean := cacher.GetBean(tableName, sid) - if bean == nil || reflect.ValueOf(bean).Elem().Type() != t { - ides = append(ides, id) - ididxes[sid] = idx - } else { - session.engine.logger.Debug("[cacheFind] cache hit bean:", tableName, id, bean) - - pk := session.engine.IdOf(bean) - xid, err := pk.ToString() - if err != nil { - return err - } - - if sid != xid { - session.engine.logger.Error("[cacheFind] error cache", xid, sid, bean) - return ErrCacheFailed - } - temps[idx] = bean - } - } - - if len(ides) > 0 { - slices := reflect.New(reflect.SliceOf(t)) - beans := slices.Interface() - - if len(table.PrimaryKeys) == 1 { - ff := make([]interface{}, 0, len(ides)) - for _, ie := range ides { - ff = append(ff, ie[0]) - } - - session.In("`"+table.PrimaryKeys[0]+"`", ff...) - } else { - for _, ie := range ides { - cond := builder.NewCond() - for i, name := range table.PrimaryKeys { - cond = cond.And(builder.Eq{"`" + name + "`": ie[i]}) - } - session.Or(cond) - } - } - - err = session.NoCache().Table(tableName).find(beans) - if err != nil { - return err - } - - vs := reflect.Indirect(reflect.ValueOf(beans)) - for i := 0; i < vs.Len(); i++ { - rv := vs.Index(i) - if rv.Kind() != reflect.Ptr { - rv = rv.Addr() - } - id, err := session.engine.idOfV(rv) - if err != nil { - return err - } - sid, err := id.ToString() - if err != nil { - return err - } - - bean := rv.Interface() - temps[ididxes[sid]] = bean - session.engine.logger.Debug("[cacheFind] cache bean:", tableName, id, bean, temps) - cacher.PutBean(tableName, sid, bean) - } - } - - for j := 0; j < len(temps); j++ { - bean := temps[j] - if bean == nil { - session.engine.logger.Warn("[cacheFind] cache no hit:", tableName, ids[j], temps) - // return errors.New("cache error") // !nashtsai! no need to return error, but continue instead - continue - } - if sliceValue.Kind() == reflect.Slice { - if t.Kind() == reflect.Ptr { - sliceValue.Set(reflect.Append(sliceValue, reflect.ValueOf(bean))) - } else { - sliceValue.Set(reflect.Append(sliceValue, reflect.Indirect(reflect.ValueOf(bean)))) - } - } else if sliceValue.Kind() == reflect.Map { - var key = ids[j] - keyType := sliceValue.Type().Key() - var ikey interface{} - if len(key) == 1 { - ikey, err = str2PK(fmt.Sprintf("%v", key[0]), keyType) - if err != nil { - return err - } - } else { - if keyType.Kind() != reflect.Slice { - return errors.New("table have multiple primary keys, key is not core.PK or slice") - } - ikey = key - } - - if t.Kind() == reflect.Ptr { - sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.ValueOf(bean)) - } else { - sliceValue.SetMapIndex(reflect.ValueOf(ikey), reflect.Indirect(reflect.ValueOf(bean))) - } - } - } - - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_get.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_get.go deleted file mode 100644 index cc0a2019e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_get.go +++ /dev/null @@ -1,356 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "errors" - "fmt" - "reflect" - "strconv" - - "xorm.io/core" -) - -// Get retrieve one record from database, bean's non-empty fields -// will be as conditions -func (session *Session) Get(bean interface{}) (bool, error) { - if session.isAutoClose { - defer session.Close() - } - return session.get(bean) -} - -func (session *Session) get(bean interface{}) (bool, error) { - defer session.resetStatement() - - if session.statement.lastError != nil { - return false, session.statement.lastError - } - - beanValue := reflect.ValueOf(bean) - if beanValue.Kind() != reflect.Ptr { - return false, errors.New("needs a pointer to a value") - } else if beanValue.Elem().Kind() == reflect.Ptr { - return false, errors.New("a pointer to a pointer is not allowed") - } - - if beanValue.Elem().Kind() == reflect.Struct { - if err := session.statement.setRefBean(bean); err != nil { - return false, err - } - } - - var sqlStr string - var args []interface{} - var err error - - if session.statement.RawSQL == "" { - if len(session.statement.TableName()) <= 0 { - return false, ErrTableNotFound - } - session.statement.Limit(1) - sqlStr, args, err = session.statement.genGetSQL(bean) - if err != nil { - return false, err - } - } else { - sqlStr = session.statement.RawSQL - args = session.statement.RawParams - } - - table := session.statement.RefTable - - if session.canCache() && beanValue.Elem().Kind() == reflect.Struct { - if cacher := session.engine.getCacher(session.statement.TableName()); cacher != nil && - !session.statement.unscoped { - has, err := session.cacheGet(bean, sqlStr, args...) - if err != ErrCacheFailed { - return has, err - } - } - } - - context := session.statement.context - if context != nil { - res := context.Get(fmt.Sprintf("%v-%v", sqlStr, args)) - if res != nil { - session.engine.logger.Debug("hit context cache", sqlStr) - - structValue := reflect.Indirect(reflect.ValueOf(bean)) - structValue.Set(reflect.Indirect(reflect.ValueOf(res))) - session.lastSQL = "" - session.lastSQLArgs = nil - return true, nil - } - } - - has, err := session.nocacheGet(beanValue.Elem().Kind(), table, bean, sqlStr, args...) - if err != nil || !has { - return has, err - } - - if context != nil { - context.Put(fmt.Sprintf("%v-%v", sqlStr, args), bean) - } - - return true, nil -} - -func (session *Session) nocacheGet(beanKind reflect.Kind, table *core.Table, bean interface{}, sqlStr string, args ...interface{}) (bool, error) { - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return false, err - } - defer rows.Close() - - if !rows.Next() { - if rows.Err() != nil { - return false, rows.Err() - } - return false, nil - } - - switch bean.(type) { - case sql.NullInt64, sql.NullBool, sql.NullFloat64, sql.NullString: - return true, rows.Scan(&bean) - case *sql.NullInt64, *sql.NullBool, *sql.NullFloat64, *sql.NullString: - return true, rows.Scan(bean) - case *string: - var res sql.NullString - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*string)) = res.String - } - return true, nil - case *int: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*int)) = int(res.Int64) - } - return true, nil - case *int8: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*int8)) = int8(res.Int64) - } - return true, nil - case *int16: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*int16)) = int16(res.Int64) - } - return true, nil - case *int32: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*int32)) = int32(res.Int64) - } - return true, nil - case *int64: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*int64)) = int64(res.Int64) - } - return true, nil - case *uint: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*uint)) = uint(res.Int64) - } - return true, nil - case *uint8: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*uint8)) = uint8(res.Int64) - } - return true, nil - case *uint16: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*uint16)) = uint16(res.Int64) - } - return true, nil - case *uint32: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*uint32)) = uint32(res.Int64) - } - return true, nil - case *uint64: - var res sql.NullInt64 - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*uint64)) = uint64(res.Int64) - } - return true, nil - case *bool: - var res sql.NullBool - if err := rows.Scan(&res); err != nil { - return true, err - } - if res.Valid { - *(bean.(*bool)) = res.Bool - } - return true, nil - } - - switch beanKind { - case reflect.Struct: - fields, err := rows.Columns() - if err != nil { - // WARN: Alougth rows return true, but get fields failed - return true, err - } - - scanResults, err := session.row2Slice(rows, fields, bean) - if err != nil { - return false, err - } - // close it before covert data - rows.Close() - - dataStruct := rValue(bean) - _, err = session.slice2Bean(scanResults, fields, bean, &dataStruct, table) - if err != nil { - return true, err - } - - return true, session.executeProcessors() - case reflect.Slice: - err = rows.ScanSlice(bean) - case reflect.Map: - err = rows.ScanMap(bean) - case reflect.String, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, - reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - err = rows.Scan(bean) - default: - err = rows.Scan(bean) - } - - return true, err -} - -func (session *Session) cacheGet(bean interface{}, sqlStr string, args ...interface{}) (has bool, err error) { - // if has no reftable, then don't use cache currently - if !session.canCache() { - return false, ErrCacheFailed - } - - for _, filter := range session.engine.dialect.Filters() { - sqlStr = filter.Do(sqlStr, session.engine.dialect, session.statement.RefTable) - } - newsql := session.statement.convertIDSQL(sqlStr) - if newsql == "" { - return false, ErrCacheFailed - } - - tableName := session.statement.TableName() - cacher := session.engine.getCacher(tableName) - - session.engine.logger.Debug("[cacheGet] find sql:", newsql, args) - table := session.statement.RefTable - ids, err := core.GetCacheSql(cacher, tableName, newsql, args) - if err != nil { - var res = make([]string, len(table.PrimaryKeys)) - rows, err := session.NoCache().queryRows(newsql, args...) - if err != nil { - return false, err - } - defer rows.Close() - - if rows.Next() { - err = rows.ScanSlice(&res) - if err != nil { - return false, err - } - } else { - return false, ErrCacheFailed - } - - var pk core.PK = make([]interface{}, len(table.PrimaryKeys)) - for i, col := range table.PKColumns() { - if col.SQLType.IsText() { - pk[i] = res[i] - } else if col.SQLType.IsNumeric() { - n, err := strconv.ParseInt(res[i], 10, 64) - if err != nil { - return false, err - } - pk[i] = n - } else { - return false, errors.New("unsupported") - } - } - - ids = []core.PK{pk} - session.engine.logger.Debug("[cacheGet] cache ids:", newsql, ids) - err = core.PutCacheSql(cacher, ids, tableName, newsql, args) - if err != nil { - return false, err - } - } else { - session.engine.logger.Debug("[cacheGet] cache hit sql:", newsql, ids) - } - - if len(ids) > 0 { - structValue := reflect.Indirect(reflect.ValueOf(bean)) - id := ids[0] - session.engine.logger.Debug("[cacheGet] get bean:", tableName, id) - sid, err := id.ToString() - if err != nil { - return false, err - } - cacheBean := cacher.GetBean(tableName, sid) - if cacheBean == nil { - cacheBean = bean - has, err = session.nocacheGet(reflect.Struct, table, cacheBean, sqlStr, args...) - if err != nil || !has { - return has, err - } - - session.engine.logger.Debug("[cacheGet] cache bean:", tableName, id, cacheBean) - cacher.PutBean(tableName, sid, cacheBean) - } else { - session.engine.logger.Debug("[cacheGet] cache hit bean:", tableName, id, cacheBean) - has = true - } - structValue.Set(reflect.Indirect(reflect.ValueOf(cacheBean))) - - return has, nil - } - return false, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_insert.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_insert.go deleted file mode 100644 index 1e19ce7a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_insert.go +++ /dev/null @@ -1,878 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "reflect" - "sort" - "strconv" - "strings" - - "xorm.io/builder" - "xorm.io/core" -) - -// Insert insert one or more beans -func (session *Session) Insert(beans ...interface{}) (int64, error) { - var affected int64 - var err error - - if session.isAutoClose { - defer session.Close() - } - - session.autoResetStatement = false - defer func() { - session.autoResetStatement = true - session.resetStatement() - }() - - for _, bean := range beans { - switch bean.(type) { - case map[string]interface{}: - cnt, err := session.insertMapInterface(bean.(map[string]interface{})) - if err != nil { - return affected, err - } - affected += cnt - case []map[string]interface{}: - s := bean.([]map[string]interface{}) - for i := 0; i < len(s); i++ { - cnt, err := session.insertMapInterface(s[i]) - if err != nil { - return affected, err - } - affected += cnt - } - case map[string]string: - cnt, err := session.insertMapString(bean.(map[string]string)) - if err != nil { - return affected, err - } - affected += cnt - case []map[string]string: - s := bean.([]map[string]string) - for i := 0; i < len(s); i++ { - cnt, err := session.insertMapString(s[i]) - if err != nil { - return affected, err - } - affected += cnt - } - default: - sliceValue := reflect.Indirect(reflect.ValueOf(bean)) - if sliceValue.Kind() == reflect.Slice { - size := sliceValue.Len() - if size > 0 { - if session.engine.SupportInsertMany() { - cnt, err := session.innerInsertMulti(bean) - if err != nil { - return affected, err - } - affected += cnt - } else { - for i := 0; i < size; i++ { - cnt, err := session.innerInsert(sliceValue.Index(i).Interface()) - if err != nil { - return affected, err - } - affected += cnt - } - } - } - } else { - cnt, err := session.innerInsert(bean) - if err != nil { - return affected, err - } - affected += cnt - } - } - } - - return affected, err -} - -func (session *Session) innerInsertMulti(rowsSlicePtr interface{}) (int64, error) { - sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) - if sliceValue.Kind() != reflect.Slice { - return 0, errors.New("needs a pointer to a slice") - } - - if sliceValue.Len() <= 0 { - return 0, errors.New("could not insert a empty slice") - } - - if err := session.statement.setRefBean(sliceValue.Index(0).Interface()); err != nil { - return 0, err - } - - tableName := session.statement.TableName() - if len(tableName) <= 0 { - return 0, ErrTableNotFound - } - - table := session.statement.RefTable - size := sliceValue.Len() - - var colNames []string - var colMultiPlaces []string - var args []interface{} - var cols []*core.Column - - for i := 0; i < size; i++ { - v := sliceValue.Index(i) - vv := reflect.Indirect(v) - elemValue := v.Interface() - var colPlaces []string - - // handle BeforeInsertProcessor - // !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi?? - for _, closure := range session.beforeClosures { - closure(elemValue) - } - - if processor, ok := interface{}(elemValue).(BeforeInsertProcessor); ok { - processor.BeforeInsert() - } - // -- - - if i == 0 { - for _, col := range table.Columns() { - ptrFieldValue, err := col.ValueOfV(&vv) - if err != nil { - return 0, err - } - fieldValue := *ptrFieldValue - if col.IsAutoIncrement && isZero(fieldValue.Interface()) { - continue - } - if col.MapType == core.ONLYFROMDB { - continue - } - if col.IsDeleted { - continue - } - if session.statement.omitColumnMap.contain(col.Name) { - continue - } - if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) { - continue - } - if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime { - val, t := session.engine.nowTime(col) - args = append(args, val) - - var colName = col.Name - session.afterClosures = append(session.afterClosures, func(bean interface{}) { - col := table.GetColumn(colName) - setColumnTime(bean, col, t) - }) - } else if col.IsVersion && session.statement.checkVersion { - args = append(args, 1) - var colName = col.Name - session.afterClosures = append(session.afterClosures, func(bean interface{}) { - col := table.GetColumn(colName) - setColumnInt(bean, col, 1) - }) - } else { - arg, err := session.value2Interface(col, fieldValue) - if err != nil { - return 0, err - } - args = append(args, arg) - } - - colNames = append(colNames, col.Name) - cols = append(cols, col) - colPlaces = append(colPlaces, "?") - } - } else { - for _, col := range cols { - ptrFieldValue, err := col.ValueOfV(&vv) - if err != nil { - return 0, err - } - fieldValue := *ptrFieldValue - - if col.IsAutoIncrement && isZero(fieldValue.Interface()) { - continue - } - if col.MapType == core.ONLYFROMDB { - continue - } - if col.IsDeleted { - continue - } - if session.statement.omitColumnMap.contain(col.Name) { - continue - } - if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) { - continue - } - if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime { - val, t := session.engine.nowTime(col) - args = append(args, val) - - var colName = col.Name - session.afterClosures = append(session.afterClosures, func(bean interface{}) { - col := table.GetColumn(colName) - setColumnTime(bean, col, t) - }) - } else if col.IsVersion && session.statement.checkVersion { - args = append(args, 1) - var colName = col.Name - session.afterClosures = append(session.afterClosures, func(bean interface{}) { - col := table.GetColumn(colName) - setColumnInt(bean, col, 1) - }) - } else { - arg, err := session.value2Interface(col, fieldValue) - if err != nil { - return 0, err - } - args = append(args, arg) - } - - colPlaces = append(colPlaces, "?") - } - } - colMultiPlaces = append(colMultiPlaces, strings.Join(colPlaces, ", ")) - } - cleanupProcessorsClosures(&session.beforeClosures) - - var sql string - if session.engine.dialect.DBType() == core.ORACLE { - temp := fmt.Sprintf(") INTO %s (%v) VALUES (", - session.engine.Quote(tableName), - quoteColumns(colNames, session.engine.Quote, ",")) - sql = fmt.Sprintf("INSERT ALL INTO %s (%v) VALUES (%v) SELECT 1 FROM DUAL", - session.engine.Quote(tableName), - quoteColumns(colNames, session.engine.Quote, ","), - strings.Join(colMultiPlaces, temp)) - } else { - sql = fmt.Sprintf("INSERT INTO %s (%v) VALUES (%v)", - session.engine.Quote(tableName), - quoteColumns(colNames, session.engine.Quote, ","), - strings.Join(colMultiPlaces, "),(")) - } - res, err := session.exec(sql, args...) - if err != nil { - return 0, err - } - - session.cacheInsert(tableName) - - lenAfterClosures := len(session.afterClosures) - for i := 0; i < size; i++ { - elemValue := reflect.Indirect(sliceValue.Index(i)).Addr().Interface() - - // handle AfterInsertProcessor - if session.isAutoCommit { - // !nashtsai! does user expect it's same slice to passed closure when using Before()/After() when insert multi?? - for _, closure := range session.afterClosures { - closure(elemValue) - } - if processor, ok := interface{}(elemValue).(AfterInsertProcessor); ok { - processor.AfterInsert() - } - } else { - if lenAfterClosures > 0 { - if value, has := session.afterInsertBeans[elemValue]; has && value != nil { - *value = append(*value, session.afterClosures...) - } else { - afterClosures := make([]func(interface{}), lenAfterClosures) - copy(afterClosures, session.afterClosures) - session.afterInsertBeans[elemValue] = &afterClosures - } - } else { - if _, ok := interface{}(elemValue).(AfterInsertProcessor); ok { - session.afterInsertBeans[elemValue] = nil - } - } - } - } - - cleanupProcessorsClosures(&session.afterClosures) - return res.RowsAffected() -} - -// InsertMulti insert multiple records -func (session *Session) InsertMulti(rowsSlicePtr interface{}) (int64, error) { - if session.isAutoClose { - defer session.Close() - } - - sliceValue := reflect.Indirect(reflect.ValueOf(rowsSlicePtr)) - if sliceValue.Kind() != reflect.Slice { - return 0, ErrParamsType - - } - - if sliceValue.Len() <= 0 { - return 0, nil - } - - return session.innerInsertMulti(rowsSlicePtr) -} - -func (session *Session) innerInsert(bean interface{}) (int64, error) { - if err := session.statement.setRefBean(bean); err != nil { - return 0, err - } - if len(session.statement.TableName()) <= 0 { - return 0, ErrTableNotFound - } - - table := session.statement.RefTable - - // handle BeforeInsertProcessor - for _, closure := range session.beforeClosures { - closure(bean) - } - cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used - - if processor, ok := interface{}(bean).(BeforeInsertProcessor); ok { - processor.BeforeInsert() - } - - colNames, args, err := session.genInsertColumns(bean) - if err != nil { - return 0, err - } - - exprs := session.statement.exprColumns - colPlaces := strings.Repeat("?, ", len(colNames)) - if exprs.Len() <= 0 && len(colPlaces) > 0 { - colPlaces = colPlaces[0 : len(colPlaces)-2] - } - - var tableName = session.statement.TableName() - var output string - if session.engine.dialect.DBType() == core.MSSQL && len(table.AutoIncrement) > 0 { - output = fmt.Sprintf(" OUTPUT Inserted.%s", table.AutoIncrement) - } - - var buf = builder.NewWriter() - if _, err := buf.WriteString(fmt.Sprintf("INSERT INTO %s", session.engine.Quote(tableName))); err != nil { - return 0, err - } - - if len(colPlaces) <= 0 { - if session.engine.dialect.DBType() == core.MYSQL { - if _, err := buf.WriteString(" VALUES ()"); err != nil { - return 0, err - } - } else { - if _, err := buf.WriteString(fmt.Sprintf("%s DEFAULT VALUES", output)); err != nil { - return 0, err - } - } - } else { - if _, err := buf.WriteString(" ("); err != nil { - return 0, err - } - - if err := writeStrings(buf, append(colNames, exprs.colNames...), "`", "`"); err != nil { - return 0, err - } - - if session.statement.cond.IsValid() { - if _, err := buf.WriteString(fmt.Sprintf(")%s SELECT ", output)); err != nil { - return 0, err - } - - if err := session.statement.writeArgs(buf, args); err != nil { - return 0, err - } - - if len(exprs.args) > 0 { - if _, err := buf.WriteString(","); err != nil { - return 0, err - } - } - if err := exprs.writeArgs(buf); err != nil { - return 0, err - } - - if _, err := buf.WriteString(fmt.Sprintf(" FROM %v WHERE ", session.engine.Quote(tableName))); err != nil { - return 0, err - } - - if err := session.statement.cond.WriteTo(buf); err != nil { - return 0, err - } - } else { - buf.Append(args...) - - if _, err := buf.WriteString(fmt.Sprintf(")%s VALUES (%v", - output, - colPlaces)); err != nil { - return 0, err - } - - if err := exprs.writeArgs(buf); err != nil { - return 0, err - } - - if _, err := buf.WriteString(")"); err != nil { - return 0, err - } - } - } - - if len(table.AutoIncrement) > 0 && session.engine.dialect.DBType() == core.POSTGRES { - if _, err := buf.WriteString(" RETURNING " + session.engine.Quote(table.AutoIncrement)); err != nil { - return 0, err - } - } - - sqlStr := buf.String() - args = buf.Args() - - handleAfterInsertProcessorFunc := func(bean interface{}) { - if session.isAutoCommit { - for _, closure := range session.afterClosures { - closure(bean) - } - if processor, ok := interface{}(bean).(AfterInsertProcessor); ok { - processor.AfterInsert() - } - } else { - lenAfterClosures := len(session.afterClosures) - if lenAfterClosures > 0 { - if value, has := session.afterInsertBeans[bean]; has && value != nil { - *value = append(*value, session.afterClosures...) - } else { - afterClosures := make([]func(interface{}), lenAfterClosures) - copy(afterClosures, session.afterClosures) - session.afterInsertBeans[bean] = &afterClosures - } - - } else { - if _, ok := interface{}(bean).(AfterInsertProcessor); ok { - session.afterInsertBeans[bean] = nil - } - } - } - cleanupProcessorsClosures(&session.afterClosures) // cleanup after used - } - - // for postgres, many of them didn't implement lastInsertId, so we should - // implemented it ourself. - if session.engine.dialect.DBType() == core.ORACLE && len(table.AutoIncrement) > 0 { - res, err := session.queryBytes("select seq_atable.currval from dual", args...) - if err != nil { - return 0, err - } - - defer handleAfterInsertProcessorFunc(bean) - - session.cacheInsert(tableName) - - if table.Version != "" && session.statement.checkVersion { - verValue, err := table.VersionColumn().ValueOf(bean) - if err != nil { - session.engine.logger.Error(err) - } else if verValue.IsValid() && verValue.CanSet() { - session.incrVersionFieldValue(verValue) - } - } - - if len(res) < 1 { - return 0, errors.New("insert no error but not returned id") - } - - idByte := res[0][table.AutoIncrement] - id, err := strconv.ParseInt(string(idByte), 10, 64) - if err != nil || id <= 0 { - return 1, err - } - - aiValue, err := table.AutoIncrColumn().ValueOf(bean) - if err != nil { - session.engine.logger.Error(err) - } - - if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { - return 1, nil - } - - aiValue.Set(int64ToIntValue(id, aiValue.Type())) - - return 1, nil - } else if len(table.AutoIncrement) > 0 && (session.engine.dialect.DBType() == core.POSTGRES || session.engine.dialect.DBType() == core.MSSQL) { - res, err := session.queryBytes(sqlStr, args...) - - if err != nil { - return 0, err - } - defer handleAfterInsertProcessorFunc(bean) - - session.cacheInsert(tableName) - - if table.Version != "" && session.statement.checkVersion { - verValue, err := table.VersionColumn().ValueOf(bean) - if err != nil { - session.engine.logger.Error(err) - } else if verValue.IsValid() && verValue.CanSet() { - session.incrVersionFieldValue(verValue) - } - } - - if len(res) < 1 { - return 0, errors.New("insert successfully but not returned id") - } - - idByte := res[0][table.AutoIncrement] - id, err := strconv.ParseInt(string(idByte), 10, 64) - if err != nil || id <= 0 { - return 1, err - } - - aiValue, err := table.AutoIncrColumn().ValueOf(bean) - if err != nil { - session.engine.logger.Error(err) - } - - if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { - return 1, nil - } - - aiValue.Set(int64ToIntValue(id, aiValue.Type())) - - return 1, nil - } else { - res, err := session.exec(sqlStr, args...) - if err != nil { - return 0, err - } - - defer handleAfterInsertProcessorFunc(bean) - - session.cacheInsert(tableName) - - if table.Version != "" && session.statement.checkVersion { - verValue, err := table.VersionColumn().ValueOf(bean) - if err != nil { - session.engine.logger.Error(err) - } else if verValue.IsValid() && verValue.CanSet() { - session.incrVersionFieldValue(verValue) - } - } - - if table.AutoIncrement == "" { - return res.RowsAffected() - } - - var id int64 - id, err = res.LastInsertId() - if err != nil || id <= 0 { - return res.RowsAffected() - } - - aiValue, err := table.AutoIncrColumn().ValueOf(bean) - if err != nil { - session.engine.logger.Error(err) - } - - if aiValue == nil || !aiValue.IsValid() || !aiValue.CanSet() { - return res.RowsAffected() - } - - aiValue.Set(int64ToIntValue(id, aiValue.Type())) - - return res.RowsAffected() - } -} - -// InsertOne insert only one struct into database as a record. -// The in parameter bean must a struct or a point to struct. The return -// parameter is inserted and error -func (session *Session) InsertOne(bean interface{}) (int64, error) { - if session.isAutoClose { - defer session.Close() - } - - return session.innerInsert(bean) -} - -func (session *Session) cacheInsert(table string) error { - if !session.statement.UseCache { - return nil - } - cacher := session.engine.getCacher(table) - if cacher == nil { - return nil - } - session.engine.logger.Debug("[cache] clear sql:", table) - cacher.ClearIds(table) - return nil -} - -// genInsertColumns generates insert needed columns -func (session *Session) genInsertColumns(bean interface{}) ([]string, []interface{}, error) { - table := session.statement.RefTable - colNames := make([]string, 0, len(table.ColumnsSeq())) - args := make([]interface{}, 0, len(table.ColumnsSeq())) - - for _, col := range table.Columns() { - if col.MapType == core.ONLYFROMDB { - continue - } - - if col.IsDeleted { - continue - } - - if session.statement.omitColumnMap.contain(col.Name) { - continue - } - - if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) { - continue - } - - if session.statement.incrColumns.isColExist(col.Name) { - continue - } else if session.statement.decrColumns.isColExist(col.Name) { - continue - } else if session.statement.exprColumns.isColExist(col.Name) { - continue - } - - fieldValuePtr, err := col.ValueOf(bean) - if err != nil { - return nil, nil, err - } - fieldValue := *fieldValuePtr - - if col.IsAutoIncrement { - switch fieldValue.Type().Kind() { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64: - if fieldValue.Int() == 0 { - continue - } - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64: - if fieldValue.Uint() == 0 { - continue - } - case reflect.String: - if len(fieldValue.String()) == 0 { - continue - } - case reflect.Ptr: - if fieldValue.Pointer() == 0 { - continue - } - } - } - - // !evalphobia! set fieldValue as nil when column is nullable and zero-value - if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok { - if col.Nullable && isZero(fieldValue.Interface()) { - var nilValue *int - fieldValue = reflect.ValueOf(nilValue) - } - } - - if (col.IsCreated || col.IsUpdated) && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ { - // if time is non-empty, then set to auto time - val, t := session.engine.nowTime(col) - args = append(args, val) - - var colName = col.Name - session.afterClosures = append(session.afterClosures, func(bean interface{}) { - col := table.GetColumn(colName) - setColumnTime(bean, col, t) - }) - } else if col.IsVersion && session.statement.checkVersion { - args = append(args, 1) - } else { - arg, err := session.value2Interface(col, fieldValue) - if err != nil { - return colNames, args, err - } - args = append(args, arg) - } - - colNames = append(colNames, col.Name) - } - return colNames, args, nil -} - -func (session *Session) insertMapInterface(m map[string]interface{}) (int64, error) { - if len(m) == 0 { - return 0, ErrParamsType - } - - tableName := session.statement.TableName() - if len(tableName) <= 0 { - return 0, ErrTableNotFound - } - - var columns = make([]string, 0, len(m)) - exprs := session.statement.exprColumns - for k := range m { - if !exprs.isColExist(k) { - columns = append(columns, k) - } - } - sort.Strings(columns) - - var args = make([]interface{}, 0, len(m)) - for _, colName := range columns { - args = append(args, m[colName]) - } - - w := builder.NewWriter() - if session.statement.cond.IsValid() { - if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil { - return 0, err - } - - if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil { - return 0, err - } - - if _, err := w.WriteString(") SELECT "); err != nil { - return 0, err - } - - if err := session.statement.writeArgs(w, args); err != nil { - return 0, err - } - - if len(exprs.args) > 0 { - if _, err := w.WriteString(","); err != nil { - return 0, err - } - if err := exprs.writeArgs(w); err != nil { - return 0, err - } - } - - if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil { - return 0, err - } - - if err := session.statement.cond.WriteTo(w); err != nil { - return 0, err - } - } else { - qm := strings.Repeat("?,", len(columns)) - qm = qm[:len(qm)-1] - - if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil { - return 0, err - } - w.Append(args...) - } - - sql := w.String() - args = w.Args() - - if err := session.cacheInsert(tableName); err != nil { - return 0, err - } - - res, err := session.exec(sql, args...) - if err != nil { - return 0, err - } - affected, err := res.RowsAffected() - if err != nil { - return 0, err - } - return affected, nil -} - -func (session *Session) insertMapString(m map[string]string) (int64, error) { - if len(m) == 0 { - return 0, ErrParamsType - } - - tableName := session.statement.TableName() - if len(tableName) <= 0 { - return 0, ErrTableNotFound - } - - var columns = make([]string, 0, len(m)) - exprs := session.statement.exprColumns - for k := range m { - if !exprs.isColExist(k) { - columns = append(columns, k) - } - } - sort.Strings(columns) - - var args = make([]interface{}, 0, len(m)) - for _, colName := range columns { - args = append(args, m[colName]) - } - - w := builder.NewWriter() - if session.statement.cond.IsValid() { - if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (", session.engine.Quote(tableName))); err != nil { - return 0, err - } - - if err := writeStrings(w, append(columns, exprs.colNames...), "`", "`"); err != nil { - return 0, err - } - - if _, err := w.WriteString(") SELECT "); err != nil { - return 0, err - } - - if err := session.statement.writeArgs(w, args); err != nil { - return 0, err - } - - if len(exprs.args) > 0 { - if _, err := w.WriteString(","); err != nil { - return 0, err - } - if err := exprs.writeArgs(w); err != nil { - return 0, err - } - } - - if _, err := w.WriteString(fmt.Sprintf(" FROM %s WHERE ", session.engine.Quote(tableName))); err != nil { - return 0, err - } - - if err := session.statement.cond.WriteTo(w); err != nil { - return 0, err - } - } else { - qm := strings.Repeat("?,", len(columns)) - qm = qm[:len(qm)-1] - - if _, err := w.WriteString(fmt.Sprintf("INSERT INTO %s (`%s`) VALUES (%s)", session.engine.Quote(tableName), strings.Join(columns, "`,`"), qm)); err != nil { - return 0, err - } - w.Append(args...) - } - - sql := w.String() - args = w.Args() - - if err := session.cacheInsert(tableName); err != nil { - return 0, err - } - - res, err := session.exec(sql, args...) - if err != nil { - return 0, err - } - affected, err := res.RowsAffected() - if err != nil { - return 0, err - } - return affected, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_iterate.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_iterate.go deleted file mode 100644 index ca996c288..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_iterate.go +++ /dev/null @@ -1,100 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import "reflect" - -// IterFunc only use by Iterate -type IterFunc func(idx int, bean interface{}) error - -// Rows return sql.Rows compatible Rows obj, as a forward Iterator object for iterating record by record, bean's non-empty fields -// are conditions. -func (session *Session) Rows(bean interface{}) (*Rows, error) { - return newRows(session, bean) -} - -// Iterate record by record handle records from table, condiBeans's non-empty fields -// are conditions. beans could be []Struct, []*Struct, map[int64]Struct -// map[int64]*Struct -func (session *Session) Iterate(bean interface{}, fun IterFunc) error { - if session.isAutoClose { - defer session.Close() - } - - if session.statement.lastError != nil { - return session.statement.lastError - } - - if session.statement.bufferSize > 0 { - return session.bufferIterate(bean, fun) - } - - rows, err := session.Rows(bean) - if err != nil { - return err - } - defer rows.Close() - - i := 0 - for rows.Next() { - b := reflect.New(rows.beanType).Interface() - err = rows.Scan(b) - if err != nil { - return err - } - err = fun(i, b) - if err != nil { - return err - } - i++ - } - return err -} - -// BufferSize sets the buffersize for iterate -func (session *Session) BufferSize(size int) *Session { - session.statement.bufferSize = size - return session -} - -func (session *Session) bufferIterate(bean interface{}, fun IterFunc) error { - if session.isAutoClose { - defer session.Close() - } - - var bufferSize = session.statement.bufferSize - var limit = session.statement.LimitN - if limit > 0 && bufferSize > limit { - bufferSize = limit - } - var start = session.statement.Start - v := rValue(bean) - sliceType := reflect.SliceOf(v.Type()) - var idx = 0 - for { - slice := reflect.New(sliceType) - if err := session.Limit(bufferSize, start).find(slice.Interface(), bean); err != nil { - return err - } - - for i := 0; i < slice.Elem().Len(); i++ { - if err := fun(idx, slice.Elem().Index(i).Addr().Interface()); err != nil { - return err - } - idx++ - } - - start = start + slice.Elem().Len() - if limit > 0 && idx+bufferSize > limit { - bufferSize = limit - idx - } - - if bufferSize <= 0 || slice.Elem().Len() < bufferSize || idx == limit { - break - } - } - - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_query.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_query.go deleted file mode 100644 index 21c00b8d7..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_query.go +++ /dev/null @@ -1,320 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "reflect" - "strconv" - "strings" - "time" - - "xorm.io/builder" - "xorm.io/core" -) - -func (session *Session) genQuerySQL(sqlOrArgs ...interface{}) (string, []interface{}, error) { - if len(sqlOrArgs) > 0 { - return convertSQLOrArgs(sqlOrArgs...) - } - - if session.statement.RawSQL != "" { - return session.statement.RawSQL, session.statement.RawParams, nil - } - - if len(session.statement.TableName()) <= 0 { - return "", nil, ErrTableNotFound - } - - var columnStr = session.statement.ColumnStr - if len(session.statement.selectStr) > 0 { - columnStr = session.statement.selectStr - } else { - if session.statement.JoinStr == "" { - if columnStr == "" { - if session.statement.GroupByStr != "" { - columnStr = session.engine.quoteColumns(session.statement.GroupByStr) - } else { - columnStr = session.statement.genColumnStr() - } - } - } else { - if columnStr == "" { - if session.statement.GroupByStr != "" { - columnStr = session.engine.quoteColumns(session.statement.GroupByStr) - } else { - columnStr = "*" - } - } - } - if columnStr == "" { - columnStr = "*" - } - } - - if err := session.statement.processIDParam(); err != nil { - return "", nil, err - } - - condSQL, condArgs, err := builder.ToSQL(session.statement.cond) - if err != nil { - return "", nil, err - } - - args := append(session.statement.joinArgs, condArgs...) - sqlStr, err := session.statement.genSelectSQL(columnStr, condSQL, true, true) - if err != nil { - return "", nil, err - } - // for mssql and use limit - qs := strings.Count(sqlStr, "?") - if len(args)*2 == qs { - args = append(args, args...) - } - - return sqlStr, args, nil -} - -// Query runs a raw sql and return records as []map[string][]byte -func (session *Session) Query(sqlOrArgs ...interface{}) ([]map[string][]byte, error) { - if session.isAutoClose { - defer session.Close() - } - - sqlStr, args, err := session.genQuerySQL(sqlOrArgs...) - if err != nil { - return nil, err - } - - return session.queryBytes(sqlStr, args...) -} - -func value2String(rawValue *reflect.Value) (str string, err error) { - aa := reflect.TypeOf((*rawValue).Interface()) - vv := reflect.ValueOf((*rawValue).Interface()) - switch aa.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - str = strconv.FormatInt(vv.Int(), 10) - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - str = strconv.FormatUint(vv.Uint(), 10) - case reflect.Float32, reflect.Float64: - str = strconv.FormatFloat(vv.Float(), 'f', -1, 64) - case reflect.String: - str = vv.String() - case reflect.Array, reflect.Slice: - switch aa.Elem().Kind() { - case reflect.Uint8: - data := rawValue.Interface().([]byte) - str = string(data) - if str == "\x00" { - str = "0" - } - default: - err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) - } - // time type - case reflect.Struct: - if aa.ConvertibleTo(core.TimeType) { - str = vv.Convert(core.TimeType).Interface().(time.Time).Format(time.RFC3339Nano) - } else { - err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) - } - case reflect.Bool: - str = strconv.FormatBool(vv.Bool()) - case reflect.Complex128, reflect.Complex64: - str = fmt.Sprintf("%v", vv.Complex()) - /* TODO: unsupported types below - case reflect.Map: - case reflect.Ptr: - case reflect.Uintptr: - case reflect.UnsafePointer: - case reflect.Chan, reflect.Func, reflect.Interface: - */ - default: - err = fmt.Errorf("Unsupported struct type %v", vv.Type().Name()) - } - return -} - -func row2mapStr(rows *core.Rows, fields []string) (resultsMap map[string]string, err error) { - result := make(map[string]string) - scanResultContainers := make([]interface{}, len(fields)) - for i := 0; i < len(fields); i++ { - var scanResultContainer interface{} - scanResultContainers[i] = &scanResultContainer - } - if err := rows.Scan(scanResultContainers...); err != nil { - return nil, err - } - - for ii, key := range fields { - rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) - // if row is null then as empty string - if rawValue.Interface() == nil { - result[key] = "" - continue - } - - if data, err := value2String(&rawValue); err == nil { - result[key] = data - } else { - return nil, err - } - } - return result, nil -} - -func row2sliceStr(rows *core.Rows, fields []string) (results []string, err error) { - result := make([]string, 0, len(fields)) - scanResultContainers := make([]interface{}, len(fields)) - for i := 0; i < len(fields); i++ { - var scanResultContainer interface{} - scanResultContainers[i] = &scanResultContainer - } - if err := rows.Scan(scanResultContainers...); err != nil { - return nil, err - } - - for i := 0; i < len(fields); i++ { - rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[i])) - // if row is null then as empty string - if rawValue.Interface() == nil { - result = append(result, "") - continue - } - - if data, err := value2String(&rawValue); err == nil { - result = append(result, data) - } else { - return nil, err - } - } - return result, nil -} - -func rows2Strings(rows *core.Rows) (resultsSlice []map[string]string, err error) { - fields, err := rows.Columns() - if err != nil { - return nil, err - } - for rows.Next() { - result, err := row2mapStr(rows, fields) - if err != nil { - return nil, err - } - resultsSlice = append(resultsSlice, result) - } - - return resultsSlice, nil -} - -func rows2SliceString(rows *core.Rows) (resultsSlice [][]string, err error) { - fields, err := rows.Columns() - if err != nil { - return nil, err - } - for rows.Next() { - record, err := row2sliceStr(rows, fields) - if err != nil { - return nil, err - } - resultsSlice = append(resultsSlice, record) - } - - return resultsSlice, nil -} - -// QueryString runs a raw sql and return records as []map[string]string -func (session *Session) QueryString(sqlOrArgs ...interface{}) ([]map[string]string, error) { - if session.isAutoClose { - defer session.Close() - } - - sqlStr, args, err := session.genQuerySQL(sqlOrArgs...) - if err != nil { - return nil, err - } - - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return rows2Strings(rows) -} - -// QuerySliceString runs a raw sql and return records as [][]string -func (session *Session) QuerySliceString(sqlOrArgs ...interface{}) ([][]string, error) { - if session.isAutoClose { - defer session.Close() - } - - sqlStr, args, err := session.genQuerySQL(sqlOrArgs...) - if err != nil { - return nil, err - } - - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return rows2SliceString(rows) -} - -func row2mapInterface(rows *core.Rows, fields []string) (resultsMap map[string]interface{}, err error) { - resultsMap = make(map[string]interface{}, len(fields)) - scanResultContainers := make([]interface{}, len(fields)) - for i := 0; i < len(fields); i++ { - var scanResultContainer interface{} - scanResultContainers[i] = &scanResultContainer - } - if err := rows.Scan(scanResultContainers...); err != nil { - return nil, err - } - - for ii, key := range fields { - resultsMap[key] = reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])).Interface() - } - return -} - -func rows2Interfaces(rows *core.Rows) (resultsSlice []map[string]interface{}, err error) { - fields, err := rows.Columns() - if err != nil { - return nil, err - } - for rows.Next() { - result, err := row2mapInterface(rows, fields) - if err != nil { - return nil, err - } - resultsSlice = append(resultsSlice, result) - } - - return resultsSlice, nil -} - -// QueryInterface runs a raw sql and return records as []map[string]interface{} -func (session *Session) QueryInterface(sqlOrArgs ...interface{}) ([]map[string]interface{}, error) { - if session.isAutoClose { - defer session.Close() - } - - sqlStr, args, err := session.genQuerySQL(sqlOrArgs...) - if err != nil { - return nil, err - } - - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return rows2Interfaces(rows) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_raw.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_raw.go deleted file mode 100644 index 67648ef13..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_raw.go +++ /dev/null @@ -1,227 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "reflect" - "time" - - "xorm.io/builder" - "xorm.io/core" -) - -func (session *Session) queryPreprocess(sqlStr *string, paramStr ...interface{}) { - for _, filter := range session.engine.dialect.Filters() { - *sqlStr = filter.Do(*sqlStr, session.engine.dialect, session.statement.RefTable) - } - - session.lastSQL = *sqlStr - session.lastSQLArgs = paramStr -} - -func (session *Session) queryRows(sqlStr string, args ...interface{}) (*core.Rows, error) { - defer session.resetStatement() - - session.queryPreprocess(&sqlStr, args...) - - if session.engine.showSQL { - if session.engine.showExecTime { - b4ExecTime := time.Now() - defer func() { - execDuration := time.Since(b4ExecTime) - if len(args) > 0 { - session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration) - } else { - session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration) - } - }() - } else { - if len(args) > 0 { - session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args) - } else { - session.engine.logger.Infof("[SQL] %v", sqlStr) - } - } - } - - if session.isAutoCommit { - var db *core.DB - if session.sessionType == groupSession { - db = session.engine.engineGroup.Slave().DB() - } else { - db = session.DB() - } - - if session.prepareStmt { - // don't clear stmt since session will cache them - stmt, err := session.doPrepare(db, sqlStr) - if err != nil { - return nil, err - } - - rows, err := stmt.QueryContext(session.ctx, args...) - if err != nil { - return nil, err - } - return rows, nil - } - - rows, err := db.QueryContext(session.ctx, sqlStr, args...) - if err != nil { - return nil, err - } - return rows, nil - } - - rows, err := session.tx.QueryContext(session.ctx, sqlStr, args...) - if err != nil { - return nil, err - } - return rows, nil -} - -func (session *Session) queryRow(sqlStr string, args ...interface{}) *core.Row { - return core.NewRow(session.queryRows(sqlStr, args...)) -} - -func value2Bytes(rawValue *reflect.Value) ([]byte, error) { - str, err := value2String(rawValue) - if err != nil { - return nil, err - } - return []byte(str), nil -} - -func row2map(rows *core.Rows, fields []string) (resultsMap map[string][]byte, err error) { - result := make(map[string][]byte) - scanResultContainers := make([]interface{}, len(fields)) - for i := 0; i < len(fields); i++ { - var scanResultContainer interface{} - scanResultContainers[i] = &scanResultContainer - } - if err := rows.Scan(scanResultContainers...); err != nil { - return nil, err - } - - for ii, key := range fields { - rawValue := reflect.Indirect(reflect.ValueOf(scanResultContainers[ii])) - //if row is null then ignore - if rawValue.Interface() == nil { - result[key] = []byte{} - continue - } - - if data, err := value2Bytes(&rawValue); err == nil { - result[key] = data - } else { - return nil, err // !nashtsai! REVIEW, should return err or just error log? - } - } - return result, nil -} - -func rows2maps(rows *core.Rows) (resultsSlice []map[string][]byte, err error) { - fields, err := rows.Columns() - if err != nil { - return nil, err - } - for rows.Next() { - result, err := row2map(rows, fields) - if err != nil { - return nil, err - } - resultsSlice = append(resultsSlice, result) - } - - return resultsSlice, nil -} - -func (session *Session) queryBytes(sqlStr string, args ...interface{}) ([]map[string][]byte, error) { - rows, err := session.queryRows(sqlStr, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - return rows2maps(rows) -} - -func (session *Session) exec(sqlStr string, args ...interface{}) (sql.Result, error) { - defer session.resetStatement() - - session.queryPreprocess(&sqlStr, args...) - - if session.engine.showSQL { - if session.engine.showExecTime { - b4ExecTime := time.Now() - defer func() { - execDuration := time.Since(b4ExecTime) - if len(args) > 0 { - session.engine.logger.Infof("[SQL] %s %#v - took: %v", sqlStr, args, execDuration) - } else { - session.engine.logger.Infof("[SQL] %s - took: %v", sqlStr, execDuration) - } - }() - } else { - if len(args) > 0 { - session.engine.logger.Infof("[SQL] %v %#v", sqlStr, args) - } else { - session.engine.logger.Infof("[SQL] %v", sqlStr) - } - } - } - - if !session.isAutoCommit { - return session.tx.ExecContext(session.ctx, sqlStr, args...) - } - - if session.prepareStmt { - stmt, err := session.doPrepare(session.DB(), sqlStr) - if err != nil { - return nil, err - } - - res, err := stmt.ExecContext(session.ctx, args...) - if err != nil { - return nil, err - } - return res, nil - } - - return session.DB().ExecContext(session.ctx, sqlStr, args...) -} - -func convertSQLOrArgs(sqlOrArgs ...interface{}) (string, []interface{}, error) { - switch sqlOrArgs[0].(type) { - case string: - return sqlOrArgs[0].(string), sqlOrArgs[1:], nil - case *builder.Builder: - return sqlOrArgs[0].(*builder.Builder).ToSQL() - case builder.Builder: - bd := sqlOrArgs[0].(builder.Builder) - return bd.ToSQL() - } - - return "", nil, ErrUnSupportedType -} - -// Exec raw sql -func (session *Session) Exec(sqlOrArgs ...interface{}) (sql.Result, error) { - if session.isAutoClose { - defer session.Close() - } - - if len(sqlOrArgs) == 0 { - return nil, ErrUnSupportedType - } - - sqlStr, args, err := convertSQLOrArgs(sqlOrArgs...) - if err != nil { - return nil, err - } - - return session.exec(sqlStr, args...) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_schema.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_schema.go deleted file mode 100644 index 5e576c29a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_schema.go +++ /dev/null @@ -1,430 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "fmt" - "strings" - - "xorm.io/core" -) - -// Ping test if database is ok -func (session *Session) Ping() error { - if session.isAutoClose { - defer session.Close() - } - - session.engine.logger.Infof("PING DATABASE %v", session.engine.DriverName()) - return session.DB().PingContext(session.ctx) -} - -// CreateTable create a table according a bean -func (session *Session) CreateTable(bean interface{}) error { - if session.isAutoClose { - defer session.Close() - } - - return session.createTable(bean) -} - -func (session *Session) createTable(bean interface{}) error { - if err := session.statement.setRefBean(bean); err != nil { - return err - } - - sqlStr := session.statement.genCreateTableSQL() - _, err := session.exec(sqlStr) - return err -} - -// CreateIndexes create indexes -func (session *Session) CreateIndexes(bean interface{}) error { - if session.isAutoClose { - defer session.Close() - } - - return session.createIndexes(bean) -} - -func (session *Session) createIndexes(bean interface{}) error { - if err := session.statement.setRefBean(bean); err != nil { - return err - } - - sqls := session.statement.genIndexSQL() - for _, sqlStr := range sqls { - _, err := session.exec(sqlStr) - if err != nil { - return err - } - } - return nil -} - -// CreateUniques create uniques -func (session *Session) CreateUniques(bean interface{}) error { - if session.isAutoClose { - defer session.Close() - } - return session.createUniques(bean) -} - -func (session *Session) createUniques(bean interface{}) error { - if err := session.statement.setRefBean(bean); err != nil { - return err - } - - sqls := session.statement.genUniqueSQL() - for _, sqlStr := range sqls { - _, err := session.exec(sqlStr) - if err != nil { - return err - } - } - return nil -} - -// DropIndexes drop indexes -func (session *Session) DropIndexes(bean interface{}) error { - if session.isAutoClose { - defer session.Close() - } - - return session.dropIndexes(bean) -} - -func (session *Session) dropIndexes(bean interface{}) error { - if err := session.statement.setRefBean(bean); err != nil { - return err - } - - sqls := session.statement.genDelIndexSQL() - for _, sqlStr := range sqls { - _, err := session.exec(sqlStr) - if err != nil { - return err - } - } - return nil -} - -// DropTable drop table will drop table if exist, if drop failed, it will return error -func (session *Session) DropTable(beanOrTableName interface{}) error { - if session.isAutoClose { - defer session.Close() - } - - return session.dropTable(beanOrTableName) -} - -func (session *Session) dropTable(beanOrTableName interface{}) error { - tableName := session.engine.TableName(beanOrTableName) - var needDrop = true - if !session.engine.dialect.SupportDropIfExists() { - sqlStr, args := session.engine.dialect.TableCheckSql(tableName) - results, err := session.queryBytes(sqlStr, args...) - if err != nil { - return err - } - needDrop = len(results) > 0 - } - - if needDrop { - sqlStr := session.engine.Dialect().DropTableSql(session.engine.TableName(tableName, true)) - _, err := session.exec(sqlStr) - return err - } - return nil -} - -// IsTableExist if a table is exist -func (session *Session) IsTableExist(beanOrTableName interface{}) (bool, error) { - if session.isAutoClose { - defer session.Close() - } - - tableName := session.engine.TableName(beanOrTableName) - - return session.isTableExist(tableName) -} - -func (session *Session) isTableExist(tableName string) (bool, error) { - sqlStr, args := session.engine.dialect.TableCheckSql(tableName) - results, err := session.queryBytes(sqlStr, args...) - return len(results) > 0, err -} - -// IsTableEmpty if table have any records -func (session *Session) IsTableEmpty(bean interface{}) (bool, error) { - if session.isAutoClose { - defer session.Close() - } - return session.isTableEmpty(session.engine.TableName(bean)) -} - -func (session *Session) isTableEmpty(tableName string) (bool, error) { - var total int64 - sqlStr := fmt.Sprintf("select count(*) from %s", session.engine.Quote(session.engine.TableName(tableName, true))) - err := session.queryRow(sqlStr).Scan(&total) - if err != nil { - if err == sql.ErrNoRows { - err = nil - } - return true, err - } - - return total == 0, nil -} - -// find if index is exist according cols -func (session *Session) isIndexExist2(tableName string, cols []string, unique bool) (bool, error) { - indexes, err := session.engine.dialect.GetIndexes(tableName) - if err != nil { - return false, err - } - - for _, index := range indexes { - if sliceEq(index.Cols, cols) { - if unique { - return index.Type == core.UniqueType, nil - } - return index.Type == core.IndexType, nil - } - } - return false, nil -} - -func (session *Session) addColumn(colName string) error { - col := session.statement.RefTable.GetColumn(colName) - sql, args := session.statement.genAddColumnStr(col) - _, err := session.exec(sql, args...) - return err -} - -func (session *Session) addIndex(tableName, idxName string) error { - index := session.statement.RefTable.Indexes[idxName] - sqlStr := session.engine.dialect.CreateIndexSql(tableName, index) - _, err := session.exec(sqlStr) - return err -} - -func (session *Session) addUnique(tableName, uqeName string) error { - index := session.statement.RefTable.Indexes[uqeName] - sqlStr := session.engine.dialect.CreateIndexSql(tableName, index) - _, err := session.exec(sqlStr) - return err -} - -// Sync2 synchronize structs to database tables -func (session *Session) Sync2(beans ...interface{}) error { - engine := session.engine - - if session.isAutoClose { - session.isAutoClose = false - defer session.Close() - } - - tables, err := engine.dialect.GetTables() - if err != nil { - return err - } - - session.autoResetStatement = false - defer func() { - session.autoResetStatement = true - session.resetStatement() - }() - - for _, bean := range beans { - v := rValue(bean) - table, err := engine.mapType(v) - if err != nil { - return err - } - var tbName string - if len(session.statement.AltTableName) > 0 { - tbName = session.statement.AltTableName - } else { - tbName = engine.TableName(bean) - } - tbNameWithSchema := engine.tbNameWithSchema(tbName) - - var oriTable *core.Table - for _, tb := range tables { - if strings.EqualFold(engine.tbNameWithSchema(tb.Name), engine.tbNameWithSchema(tbName)) { - oriTable = tb - break - } - } - - // this is a new table - if oriTable == nil { - err = session.StoreEngine(session.statement.StoreEngine).createTable(bean) - if err != nil { - return err - } - - err = session.createUniques(bean) - if err != nil { - return err - } - - err = session.createIndexes(bean) - if err != nil { - return err - } - continue - } - - // this will modify an old table - if err = engine.loadTableInfo(oriTable); err != nil { - return err - } - - // check columns - for _, col := range table.Columns() { - var oriCol *core.Column - for _, col2 := range oriTable.Columns() { - if strings.EqualFold(col.Name, col2.Name) { - oriCol = col2 - break - } - } - - // column is not exist on table - if oriCol == nil { - session.statement.RefTable = table - session.statement.tableName = tbNameWithSchema - if err = session.addColumn(col.Name); err != nil { - return err - } - continue - } - - err = nil - expectedType := engine.dialect.SqlType(col) - curType := engine.dialect.SqlType(oriCol) - if expectedType != curType { - if expectedType == core.Text && - strings.HasPrefix(curType, core.Varchar) { - // currently only support mysql & postgres - if engine.dialect.DBType() == core.MYSQL || - engine.dialect.DBType() == core.POSTGRES { - engine.logger.Infof("Table %s column %s change type from %s to %s\n", - tbNameWithSchema, col.Name, curType, expectedType) - _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) - } else { - engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s\n", - tbNameWithSchema, col.Name, curType, expectedType) - } - } else if strings.HasPrefix(curType, core.Varchar) && strings.HasPrefix(expectedType, core.Varchar) { - if engine.dialect.DBType() == core.MYSQL { - if oriCol.Length < col.Length { - engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", - tbNameWithSchema, col.Name, oriCol.Length, col.Length) - _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) - } - } - } else { - if !(strings.HasPrefix(curType, expectedType) && curType[len(expectedType)] == '(') { - engine.logger.Warnf("Table %s column %s db type is %s, struct type is %s", - tbNameWithSchema, col.Name, curType, expectedType) - } - } - } else if expectedType == core.Varchar { - if engine.dialect.DBType() == core.MYSQL { - if oriCol.Length < col.Length { - engine.logger.Infof("Table %s column %s change type from varchar(%d) to varchar(%d)\n", - tbNameWithSchema, col.Name, oriCol.Length, col.Length) - _, err = session.exec(engine.dialect.ModifyColumnSql(tbNameWithSchema, col)) - } - } - } - - if col.Default != oriCol.Default { - if (col.SQLType.Name == core.Bool || col.SQLType.Name == core.Boolean) && - ((strings.EqualFold(col.Default, "true") && oriCol.Default == "1") || - (strings.EqualFold(col.Default, "false") && oriCol.Default == "0")) { - } else { - engine.logger.Warnf("Table %s Column %s db default is %s, struct default is %s", - tbName, col.Name, oriCol.Default, col.Default) - } - } - if col.Nullable != oriCol.Nullable { - engine.logger.Warnf("Table %s Column %s db nullable is %v, struct nullable is %v", - tbName, col.Name, oriCol.Nullable, col.Nullable) - } - - if err != nil { - return err - } - } - - var foundIndexNames = make(map[string]bool) - var addedNames = make(map[string]*core.Index) - - for name, index := range table.Indexes { - var oriIndex *core.Index - for name2, index2 := range oriTable.Indexes { - if index.Equal(index2) { - oriIndex = index2 - foundIndexNames[name2] = true - break - } - } - - if oriIndex != nil { - if oriIndex.Type != index.Type { - sql := engine.dialect.DropIndexSql(tbNameWithSchema, oriIndex) - _, err = session.exec(sql) - if err != nil { - return err - } - oriIndex = nil - } - } - - if oriIndex == nil { - addedNames[name] = index - } - } - - for name2, index2 := range oriTable.Indexes { - if _, ok := foundIndexNames[name2]; !ok { - sql := engine.dialect.DropIndexSql(tbNameWithSchema, index2) - _, err = session.exec(sql) - if err != nil { - return err - } - } - } - - for name, index := range addedNames { - if index.Type == core.UniqueType { - session.statement.RefTable = table - session.statement.tableName = tbNameWithSchema - err = session.addUnique(tbNameWithSchema, name) - } else if index.Type == core.IndexType { - session.statement.RefTable = table - session.statement.tableName = tbNameWithSchema - err = session.addIndex(tbNameWithSchema, name) - } - if err != nil { - return err - } - } - - // check all the columns which removed from struct fields but left on database tables. - for _, colName := range oriTable.ColumnsSeq() { - if table.GetColumn(colName) == nil { - engine.logger.Warnf("Table %s has column %s but struct has not related field", engine.TableName(oriTable.Name, true), colName) - } - } - } - - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_stats.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_stats.go deleted file mode 100644 index c2cac8306..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_stats.go +++ /dev/null @@ -1,98 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "errors" - "reflect" -) - -// Count counts the records. bean's non-empty fields -// are conditions. -func (session *Session) Count(bean ...interface{}) (int64, error) { - if session.isAutoClose { - defer session.Close() - } - - var sqlStr string - var args []interface{} - var err error - if session.statement.RawSQL == "" { - sqlStr, args, err = session.statement.genCountSQL(bean...) - if err != nil { - return 0, err - } - } else { - sqlStr = session.statement.RawSQL - args = session.statement.RawParams - } - - var total int64 - err = session.queryRow(sqlStr, args...).Scan(&total) - if err == sql.ErrNoRows || err == nil { - return total, nil - } - - return 0, err -} - -// sum call sum some column. bean's non-empty fields are conditions. -func (session *Session) sum(res interface{}, bean interface{}, columnNames ...string) error { - if session.isAutoClose { - defer session.Close() - } - - v := reflect.ValueOf(res) - if v.Kind() != reflect.Ptr { - return errors.New("need a pointer to a variable") - } - - var isSlice = v.Elem().Kind() == reflect.Slice - var sqlStr string - var args []interface{} - var err error - if len(session.statement.RawSQL) == 0 { - sqlStr, args, err = session.statement.genSumSQL(bean, columnNames...) - if err != nil { - return err - } - } else { - sqlStr = session.statement.RawSQL - args = session.statement.RawParams - } - - if isSlice { - err = session.queryRow(sqlStr, args...).ScanSlice(res) - } else { - err = session.queryRow(sqlStr, args...).Scan(res) - } - if err == sql.ErrNoRows || err == nil { - return nil - } - return err -} - -// Sum call sum some column. bean's non-empty fields are conditions. -func (session *Session) Sum(bean interface{}, columnName string) (res float64, err error) { - return res, session.sum(&res, bean, columnName) -} - -// SumInt call sum some column. bean's non-empty fields are conditions. -func (session *Session) SumInt(bean interface{}, columnName string) (res int64, err error) { - return res, session.sum(&res, bean, columnName) -} - -// Sums call sum some columns. bean's non-empty fields are conditions. -func (session *Session) Sums(bean interface{}, columnNames ...string) ([]float64, error) { - var res = make([]float64, len(columnNames), len(columnNames)) - return res, session.sum(&res, bean, columnNames...) -} - -// SumsInt sum specify columns and return as []int64 instead of []float64 -func (session *Session) SumsInt(bean interface{}, columnNames ...string) ([]int64, error) { - var res = make([]int64, len(columnNames), len(columnNames)) - return res, session.sum(&res, bean, columnNames...) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_test.go deleted file mode 100644 index 343f9baaa..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_test.go +++ /dev/null @@ -1,45 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestClose(t *testing.T) { - assert.NoError(t, prepareEngine()) - - sess1 := testEngine.NewSession() - sess1.Close() - assert.True(t, sess1.IsClosed()) - - sess2 := testEngine.Where("a = ?", 1) - sess2.Close() - assert.True(t, sess2.IsClosed()) -} - -func TestNullFloatStruct(t *testing.T) { - type MyNullFloat64 sql.NullFloat64 - - type MyNullFloatStruct struct { - Uuid string - Amount MyNullFloat64 - } - - assert.NoError(t, prepareEngine()) - assert.NoError(t, testEngine.Sync2(new(MyNullFloatStruct))) - - _, err := testEngine.Insert(&MyNullFloatStruct{ - Uuid: "111111", - Amount: MyNullFloat64(sql.NullFloat64{ - Float64: 0.1111, - Valid: true, - }), - }) - assert.NoError(t, err) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_tx.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_tx.go deleted file mode 100644 index ee3d473f9..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_tx.go +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -// Begin a transaction -func (session *Session) Begin() error { - if session.isAutoCommit { - tx, err := session.DB().BeginTx(session.ctx, nil) - if err != nil { - return err - } - session.isAutoCommit = false - session.isCommitedOrRollbacked = false - session.tx = tx - session.saveLastSQL("BEGIN TRANSACTION") - } - return nil -} - -// Rollback When using transaction, you can rollback if any error -func (session *Session) Rollback() error { - if !session.isAutoCommit && !session.isCommitedOrRollbacked { - session.saveLastSQL(session.engine.dialect.RollBackStr()) - session.isCommitedOrRollbacked = true - session.isAutoCommit = true - return session.tx.Rollback() - } - return nil -} - -// Commit When using transaction, Commit will commit all operations. -func (session *Session) Commit() error { - if !session.isAutoCommit && !session.isCommitedOrRollbacked { - session.saveLastSQL("COMMIT") - session.isCommitedOrRollbacked = true - session.isAutoCommit = true - var err error - if err = session.tx.Commit(); err == nil { - // handle processors after tx committed - closureCallFunc := func(closuresPtr *[]func(interface{}), bean interface{}) { - if closuresPtr != nil { - for _, closure := range *closuresPtr { - closure(bean) - } - } - } - - for bean, closuresPtr := range session.afterInsertBeans { - closureCallFunc(closuresPtr, bean) - - if processor, ok := interface{}(bean).(AfterInsertProcessor); ok { - processor.AfterInsert() - } - } - for bean, closuresPtr := range session.afterUpdateBeans { - closureCallFunc(closuresPtr, bean) - - if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok { - processor.AfterUpdate() - } - } - for bean, closuresPtr := range session.afterDeleteBeans { - closureCallFunc(closuresPtr, bean) - - if processor, ok := interface{}(bean).(AfterDeleteProcessor); ok { - processor.AfterDelete() - } - } - cleanUpFunc := func(slices *map[interface{}]*[]func(interface{})) { - if len(*slices) > 0 { - *slices = make(map[interface{}]*[]func(interface{}), 0) - } - } - cleanUpFunc(&session.afterInsertBeans) - cleanUpFunc(&session.afterUpdateBeans) - cleanUpFunc(&session.afterDeleteBeans) - } - return err - } - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_update.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_update.go deleted file mode 100644 index c5c65a452..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/session_update.go +++ /dev/null @@ -1,525 +0,0 @@ -// Copyright 2016 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "reflect" - "strconv" - "strings" - - "xorm.io/builder" - "xorm.io/core" -) - -func (session *Session) cacheUpdate(table *core.Table, tableName, sqlStr string, args ...interface{}) error { - if table == nil || - session.tx != nil { - return ErrCacheFailed - } - - oldhead, newsql := session.statement.convertUpdateSQL(sqlStr) - if newsql == "" { - return ErrCacheFailed - } - for _, filter := range session.engine.dialect.Filters() { - newsql = filter.Do(newsql, session.engine.dialect, table) - } - session.engine.logger.Debug("[cacheUpdate] new sql", oldhead, newsql) - - var nStart int - if len(args) > 0 { - if strings.Index(sqlStr, "?") > -1 { - nStart = strings.Count(oldhead, "?") - } else { - // only for pq, TODO: if any other databse? - nStart = strings.Count(oldhead, "$") - } - } - - cacher := session.engine.getCacher(tableName) - session.engine.logger.Debug("[cacheUpdate] get cache sql", newsql, args[nStart:]) - ids, err := core.GetCacheSql(cacher, tableName, newsql, args[nStart:]) - if err != nil { - rows, err := session.NoCache().queryRows(newsql, args[nStart:]...) - if err != nil { - return err - } - defer rows.Close() - - ids = make([]core.PK, 0) - for rows.Next() { - var res = make([]string, len(table.PrimaryKeys)) - err = rows.ScanSlice(&res) - if err != nil { - return err - } - var pk core.PK = make([]interface{}, len(table.PrimaryKeys)) - for i, col := range table.PKColumns() { - if col.SQLType.IsNumeric() { - n, err := strconv.ParseInt(res[i], 10, 64) - if err != nil { - return err - } - pk[i] = n - } else if col.SQLType.IsText() { - pk[i] = res[i] - } else { - return errors.New("not supported") - } - } - - ids = append(ids, pk) - } - session.engine.logger.Debug("[cacheUpdate] find updated id", ids) - } /*else { - session.engine.LogDebug("[xorm:cacheUpdate] del cached sql:", tableName, newsql, args) - cacher.DelIds(tableName, genSqlKey(newsql, args)) - }*/ - - for _, id := range ids { - sid, err := id.ToString() - if err != nil { - return err - } - if bean := cacher.GetBean(tableName, sid); bean != nil { - sqls := splitNNoCase(sqlStr, "where", 2) - if len(sqls) == 0 || len(sqls) > 2 { - return ErrCacheFailed - } - - sqls = splitNNoCase(sqls[0], "set", 2) - if len(sqls) != 2 { - return ErrCacheFailed - } - kvs := strings.Split(strings.TrimSpace(sqls[1]), ",") - - for idx, kv := range kvs { - sps := strings.SplitN(kv, "=", 2) - sps2 := strings.Split(sps[0], ".") - colName := sps2[len(sps2)-1] - // treat quote prefix, suffix and '`' as quotes - quotes := append(strings.Split(session.engine.Quote(""), ""), "`") - if strings.ContainsAny(colName, strings.Join(quotes, "")) { - colName = strings.TrimSpace(eraseAny(colName, quotes...)) - } else { - session.engine.logger.Debug("[cacheUpdate] cannot find column", tableName, colName) - return ErrCacheFailed - } - - if col := table.GetColumn(colName); col != nil { - fieldValue, err := col.ValueOf(bean) - if err != nil { - session.engine.logger.Error(err) - } else { - session.engine.logger.Debug("[cacheUpdate] set bean field", bean, colName, fieldValue.Interface()) - if col.IsVersion && session.statement.checkVersion { - session.incrVersionFieldValue(fieldValue) - } else { - fieldValue.Set(reflect.ValueOf(args[idx])) - } - } - } else { - session.engine.logger.Errorf("[cacheUpdate] ERROR: column %v is not table %v's", - colName, table.Name) - } - } - - session.engine.logger.Debug("[cacheUpdate] update cache", tableName, id, bean) - cacher.PutBean(tableName, sid, bean) - } - } - session.engine.logger.Debug("[cacheUpdate] clear cached table sql:", tableName) - cacher.ClearIds(tableName) - return nil -} - -// Update records, bean's non-empty fields are updated contents, -// condiBean' non-empty filds are conditions -// CAUTION: -// 1.bool will defaultly be updated content nor conditions -// You should call UseBool if you have bool to use. -// 2.float32 & float64 may be not inexact as conditions -func (session *Session) Update(bean interface{}, condiBean ...interface{}) (int64, error) { - if session.isAutoClose { - defer session.Close() - } - - if session.statement.lastError != nil { - return 0, session.statement.lastError - } - - v := rValue(bean) - t := v.Type() - - var colNames []string - var args []interface{} - - // handle before update processors - for _, closure := range session.beforeClosures { - closure(bean) - } - cleanupProcessorsClosures(&session.beforeClosures) // cleanup after used - if processor, ok := interface{}(bean).(BeforeUpdateProcessor); ok { - processor.BeforeUpdate() - } - // -- - - var err error - var isMap = t.Kind() == reflect.Map - var isStruct = t.Kind() == reflect.Struct - if isStruct { - if err := session.statement.setRefBean(bean); err != nil { - return 0, err - } - - if len(session.statement.TableName()) <= 0 { - return 0, ErrTableNotFound - } - - if session.statement.ColumnStr == "" { - colNames, args = session.statement.buildUpdates(bean, false, false, - false, false, true) - } else { - colNames, args, err = session.genUpdateColumns(bean) - if err != nil { - return 0, err - } - } - } else if isMap { - colNames = make([]string, 0) - args = make([]interface{}, 0) - bValue := reflect.Indirect(reflect.ValueOf(bean)) - - for _, v := range bValue.MapKeys() { - colNames = append(colNames, session.engine.Quote(v.String())+" = ?") - args = append(args, bValue.MapIndex(v).Interface()) - } - } else { - return 0, ErrParamsType - } - - table := session.statement.RefTable - - if session.statement.UseAutoTime && table != nil && table.Updated != "" { - if !session.statement.columnMap.contain(table.Updated) && - !session.statement.omitColumnMap.contain(table.Updated) { - colNames = append(colNames, session.engine.Quote(table.Updated)+" = ?") - col := table.UpdatedColumn() - val, t := session.engine.nowTime(col) - args = append(args, val) - - var colName = col.Name - if isStruct { - session.afterClosures = append(session.afterClosures, func(bean interface{}) { - col := table.GetColumn(colName) - setColumnTime(bean, col, t) - }) - } - } - } - - // for update action to like "column = column + ?" - incColumns := session.statement.incrColumns - for i, colName := range incColumns.colNames { - colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" + ?") - args = append(args, incColumns.args[i]) - } - // for update action to like "column = column - ?" - decColumns := session.statement.decrColumns - for i, colName := range decColumns.colNames { - colNames = append(colNames, session.engine.Quote(colName)+" = "+session.engine.Quote(colName)+" - ?") - args = append(args, decColumns.args[i]) - } - // for update action to like "column = expression" - exprColumns := session.statement.exprColumns - for i, colName := range exprColumns.colNames { - switch tp := exprColumns.args[i].(type) { - case string: - colNames = append(colNames, session.engine.Quote(colName)+" = "+tp) - case *builder.Builder: - subQuery, subArgs, err := builder.ToSQL(tp) - if err != nil { - return 0, err - } - colNames = append(colNames, session.engine.Quote(colName)+" = ("+subQuery+")") - args = append(args, subArgs...) - } - } - - if err = session.statement.processIDParam(); err != nil { - return 0, err - } - - var autoCond builder.Cond - if !session.statement.noAutoCondition { - condBeanIsStruct := false - if len(condiBean) > 0 { - if c, ok := condiBean[0].(map[string]interface{}); ok { - autoCond = builder.Eq(c) - } else { - ct := reflect.TypeOf(condiBean[0]) - k := ct.Kind() - if k == reflect.Ptr { - k = ct.Elem().Kind() - } - if k == reflect.Struct { - var err error - autoCond, err = session.statement.buildConds(session.statement.RefTable, condiBean[0], true, true, false, true, false) - if err != nil { - return 0, err - } - condBeanIsStruct = true - } else { - return 0, ErrConditionType - } - } - } - - if !condBeanIsStruct && table != nil { - if col := table.DeletedColumn(); col != nil && !session.statement.unscoped { // tag "deleted" is enabled - autoCond1 := session.engine.CondDeleted(session.engine.Quote(col.Name)) - - if autoCond == nil { - autoCond = autoCond1 - } else { - autoCond = autoCond.And(autoCond1) - } - } - } - } - - st := &session.statement - - var sqlStr string - var condArgs []interface{} - var condSQL string - cond := session.statement.cond.And(autoCond) - - var doIncVer = (table != nil && table.Version != "" && session.statement.checkVersion) - var verValue *reflect.Value - if doIncVer { - verValue, err = table.VersionColumn().ValueOf(bean) - if err != nil { - return 0, err - } - - cond = cond.And(builder.Eq{session.engine.Quote(table.Version): verValue.Interface()}) - colNames = append(colNames, session.engine.Quote(table.Version)+" = "+session.engine.Quote(table.Version)+" + 1") - } - - condSQL, condArgs, err = builder.ToSQL(cond) - if err != nil { - return 0, err - } - - if len(condSQL) > 0 { - condSQL = "WHERE " + condSQL - } - - if st.OrderStr != "" { - condSQL = condSQL + fmt.Sprintf(" ORDER BY %v", st.OrderStr) - } - - var tableName = session.statement.TableName() - // TODO: Oracle support needed - var top string - if st.LimitN > 0 { - if st.Engine.dialect.DBType() == core.MYSQL { - condSQL = condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) - } else if st.Engine.dialect.DBType() == core.SQLITE { - tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) - cond = cond.And(builder.Expr(fmt.Sprintf("rowid IN (SELECT rowid FROM %v %v)", - session.engine.Quote(tableName), tempCondSQL), condArgs...)) - condSQL, condArgs, err = builder.ToSQL(cond) - if err != nil { - return 0, err - } - if len(condSQL) > 0 { - condSQL = "WHERE " + condSQL - } - } else if st.Engine.dialect.DBType() == core.POSTGRES { - tempCondSQL := condSQL + fmt.Sprintf(" LIMIT %d", st.LimitN) - cond = cond.And(builder.Expr(fmt.Sprintf("CTID IN (SELECT CTID FROM %v %v)", - session.engine.Quote(tableName), tempCondSQL), condArgs...)) - condSQL, condArgs, err = builder.ToSQL(cond) - if err != nil { - return 0, err - } - - if len(condSQL) > 0 { - condSQL = "WHERE " + condSQL - } - } else if st.Engine.dialect.DBType() == core.MSSQL { - if st.OrderStr != "" && st.Engine.dialect.DBType() == core.MSSQL && - table != nil && len(table.PrimaryKeys) == 1 { - cond = builder.Expr(fmt.Sprintf("%s IN (SELECT TOP (%d) %s FROM %v%v)", - table.PrimaryKeys[0], st.LimitN, table.PrimaryKeys[0], - session.engine.Quote(tableName), condSQL), condArgs...) - - condSQL, condArgs, err = builder.ToSQL(cond) - if err != nil { - return 0, err - } - if len(condSQL) > 0 { - condSQL = "WHERE " + condSQL - } - } else { - top = fmt.Sprintf("TOP (%d) ", st.LimitN) - } - } - } - - if len(colNames) <= 0 { - return 0, errors.New("No content found to be updated") - } - - sqlStr = fmt.Sprintf("UPDATE %v%v SET %v %v", - top, - session.engine.Quote(tableName), - strings.Join(colNames, ", "), - condSQL) - - res, err := session.exec(sqlStr, append(args, condArgs...)...) - if err != nil { - return 0, err - } else if doIncVer { - if verValue != nil && verValue.IsValid() && verValue.CanSet() { - session.incrVersionFieldValue(verValue) - } - } - - if cacher := session.engine.getCacher(tableName); cacher != nil && session.statement.UseCache { - // session.cacheUpdate(table, tableName, sqlStr, args...) - session.engine.logger.Debug("[cacheUpdate] clear table ", tableName) - cacher.ClearIds(tableName) - cacher.ClearBeans(tableName) - } - - // handle after update processors - if session.isAutoCommit { - for _, closure := range session.afterClosures { - closure(bean) - } - if processor, ok := interface{}(bean).(AfterUpdateProcessor); ok { - session.engine.logger.Debug("[event]", tableName, " has after update processor") - processor.AfterUpdate() - } - } else { - lenAfterClosures := len(session.afterClosures) - if lenAfterClosures > 0 { - if value, has := session.afterUpdateBeans[bean]; has && value != nil { - *value = append(*value, session.afterClosures...) - } else { - afterClosures := make([]func(interface{}), lenAfterClosures) - copy(afterClosures, session.afterClosures) - // FIXME: if bean is a map type, it will panic because map cannot be as map key - session.afterUpdateBeans[bean] = &afterClosures - } - - } else { - if _, ok := interface{}(bean).(AfterUpdateProcessor); ok { - session.afterUpdateBeans[bean] = nil - } - } - } - cleanupProcessorsClosures(&session.afterClosures) // cleanup after used - // -- - - return res.RowsAffected() -} - -func (session *Session) genUpdateColumns(bean interface{}) ([]string, []interface{}, error) { - table := session.statement.RefTable - colNames := make([]string, 0, len(table.ColumnsSeq())) - args := make([]interface{}, 0, len(table.ColumnsSeq())) - - for _, col := range table.Columns() { - if !col.IsVersion && !col.IsCreated && !col.IsUpdated { - if session.statement.omitColumnMap.contain(col.Name) { - continue - } - } - if col.MapType == core.ONLYFROMDB { - continue - } - - fieldValuePtr, err := col.ValueOf(bean) - if err != nil { - return nil, nil, err - } - fieldValue := *fieldValuePtr - - if col.IsAutoIncrement { - switch fieldValue.Type().Kind() { - case reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int, reflect.Int64: - if fieldValue.Int() == 0 { - continue - } - case reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint, reflect.Uint64: - if fieldValue.Uint() == 0 { - continue - } - case reflect.String: - if len(fieldValue.String()) == 0 { - continue - } - case reflect.Ptr: - if fieldValue.Pointer() == 0 { - continue - } - } - } - - if (col.IsDeleted && !session.statement.unscoped) || col.IsCreated { - continue - } - - // if only update specify columns - if len(session.statement.columnMap) > 0 && !session.statement.columnMap.contain(col.Name) { - continue - } - - if session.statement.incrColumns.isColExist(col.Name) { - continue - } else if session.statement.decrColumns.isColExist(col.Name) { - continue - } else if session.statement.exprColumns.isColExist(col.Name) { - continue - } - - // !evalphobia! set fieldValue as nil when column is nullable and zero-value - if _, ok := getFlagForColumn(session.statement.nullableMap, col); ok { - if col.Nullable && isZero(fieldValue.Interface()) { - var nilValue *int - fieldValue = reflect.ValueOf(nilValue) - } - } - - if col.IsUpdated && session.statement.UseAutoTime /*&& isZero(fieldValue.Interface())*/ { - // if time is non-empty, then set to auto time - val, t := session.engine.nowTime(col) - args = append(args, val) - - var colName = col.Name - session.afterClosures = append(session.afterClosures, func(bean interface{}) { - col := table.GetColumn(colName) - setColumnTime(bean, col, t) - }) - } else if col.IsVersion && session.statement.checkVersion { - args = append(args, 1) - } else { - arg, err := session.value2Interface(col, fieldValue) - if err != nil { - return colNames, args, err - } - args = append(args, arg) - } - - colNames = append(colNames, session.engine.Quote(col.Name)+" = ?") - } - return colNames, args, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement.go deleted file mode 100644 index 67e352136..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement.go +++ /dev/null @@ -1,1256 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql/driver" - "fmt" - "reflect" - "strings" - "time" - - "xorm.io/builder" - "xorm.io/core" -) - -// Statement save all the sql info for executing SQL -type Statement struct { - RefTable *core.Table - Engine *Engine - Start int - LimitN int - idParam *core.PK - OrderStr string - JoinStr string - joinArgs []interface{} - GroupByStr string - HavingStr string - ColumnStr string - selectStr string - useAllCols bool - OmitStr string - AltTableName string - tableName string - RawSQL string - RawParams []interface{} - UseCascade bool - UseAutoJoin bool - StoreEngine string - Charset string - UseCache bool - UseAutoTime bool - noAutoCondition bool - IsDistinct bool - IsForUpdate bool - TableAlias string - allUseBool bool - checkVersion bool - unscoped bool - columnMap columnMap - omitColumnMap columnMap - mustColumnMap map[string]bool - nullableMap map[string]bool - incrColumns exprParams - decrColumns exprParams - exprColumns exprParams - cond builder.Cond - bufferSize int - context ContextCache - lastError error -} - -// Init reset all the statement's fields -func (statement *Statement) Init() { - statement.RefTable = nil - statement.Start = 0 - statement.LimitN = 0 - statement.OrderStr = "" - statement.UseCascade = true - statement.JoinStr = "" - statement.joinArgs = make([]interface{}, 0) - statement.GroupByStr = "" - statement.HavingStr = "" - statement.ColumnStr = "" - statement.OmitStr = "" - statement.columnMap = columnMap{} - statement.omitColumnMap = columnMap{} - statement.AltTableName = "" - statement.tableName = "" - statement.idParam = nil - statement.RawSQL = "" - statement.RawParams = make([]interface{}, 0) - statement.UseCache = true - statement.UseAutoTime = true - statement.noAutoCondition = false - statement.IsDistinct = false - statement.IsForUpdate = false - statement.TableAlias = "" - statement.selectStr = "" - statement.allUseBool = false - statement.useAllCols = false - statement.mustColumnMap = make(map[string]bool) - statement.nullableMap = make(map[string]bool) - statement.checkVersion = true - statement.unscoped = false - statement.incrColumns = exprParams{} - statement.decrColumns = exprParams{} - statement.exprColumns = exprParams{} - statement.cond = builder.NewCond() - statement.bufferSize = 0 - statement.context = nil - statement.lastError = nil -} - -// NoAutoCondition if you do not want convert bean's field as query condition, then use this function -func (statement *Statement) NoAutoCondition(no ...bool) *Statement { - statement.noAutoCondition = true - if len(no) > 0 { - statement.noAutoCondition = no[0] - } - return statement -} - -// Alias set the table alias -func (statement *Statement) Alias(alias string) *Statement { - statement.TableAlias = alias - return statement -} - -// SQL adds raw sql statement -func (statement *Statement) SQL(query interface{}, args ...interface{}) *Statement { - switch query.(type) { - case (*builder.Builder): - var err error - statement.RawSQL, statement.RawParams, err = query.(*builder.Builder).ToSQL() - if err != nil { - statement.lastError = err - } - case string: - statement.RawSQL = query.(string) - statement.RawParams = args - default: - statement.lastError = ErrUnSupportedSQLType - } - - return statement -} - -// Where add Where statement -func (statement *Statement) Where(query interface{}, args ...interface{}) *Statement { - return statement.And(query, args...) -} - -// And add Where & and statement -func (statement *Statement) And(query interface{}, args ...interface{}) *Statement { - switch query.(type) { - case string: - cond := builder.Expr(query.(string), args...) - statement.cond = statement.cond.And(cond) - case map[string]interface{}: - queryMap := query.(map[string]interface{}) - newMap := make(map[string]interface{}) - for k, v := range queryMap { - newMap[statement.Engine.Quote(k)] = v - } - statement.cond = statement.cond.And(builder.Eq(newMap)) - case builder.Cond: - cond := query.(builder.Cond) - statement.cond = statement.cond.And(cond) - for _, v := range args { - if vv, ok := v.(builder.Cond); ok { - statement.cond = statement.cond.And(vv) - } - } - default: - statement.lastError = ErrConditionType - } - - return statement -} - -// Or add Where & Or statement -func (statement *Statement) Or(query interface{}, args ...interface{}) *Statement { - switch query.(type) { - case string: - cond := builder.Expr(query.(string), args...) - statement.cond = statement.cond.Or(cond) - case map[string]interface{}: - cond := builder.Eq(query.(map[string]interface{})) - statement.cond = statement.cond.Or(cond) - case builder.Cond: - cond := query.(builder.Cond) - statement.cond = statement.cond.Or(cond) - for _, v := range args { - if vv, ok := v.(builder.Cond); ok { - statement.cond = statement.cond.Or(vv) - } - } - default: - // TODO: not support condition type - } - return statement -} - -// In generate "Where column IN (?) " statement -func (statement *Statement) In(column string, args ...interface{}) *Statement { - in := builder.In(statement.Engine.Quote(column), args...) - statement.cond = statement.cond.And(in) - return statement -} - -// NotIn generate "Where column NOT IN (?) " statement -func (statement *Statement) NotIn(column string, args ...interface{}) *Statement { - notIn := builder.NotIn(statement.Engine.Quote(column), args...) - statement.cond = statement.cond.And(notIn) - return statement -} - -func (statement *Statement) setRefValue(v reflect.Value) error { - var err error - statement.RefTable, err = statement.Engine.autoMapType(reflect.Indirect(v)) - if err != nil { - return err - } - statement.tableName = statement.Engine.TableName(v, true) - return nil -} - -func (statement *Statement) setRefBean(bean interface{}) error { - var err error - statement.RefTable, err = statement.Engine.autoMapType(rValue(bean)) - if err != nil { - return err - } - statement.tableName = statement.Engine.TableName(bean, true) - return nil -} - -// Auto generating update columnes and values according a struct -func (statement *Statement) buildUpdates(bean interface{}, - includeVersion, includeUpdated, includeNil, - includeAutoIncr, update bool) ([]string, []interface{}) { - engine := statement.Engine - table := statement.RefTable - allUseBool := statement.allUseBool - useAllCols := statement.useAllCols - mustColumnMap := statement.mustColumnMap - nullableMap := statement.nullableMap - columnMap := statement.columnMap - omitColumnMap := statement.omitColumnMap - unscoped := statement.unscoped - - var colNames = make([]string, 0) - var args = make([]interface{}, 0) - for _, col := range table.Columns() { - if !includeVersion && col.IsVersion { - continue - } - if col.IsCreated { - continue - } - if !includeUpdated && col.IsUpdated { - continue - } - if !includeAutoIncr && col.IsAutoIncrement { - continue - } - if col.IsDeleted && !unscoped { - continue - } - if omitColumnMap.contain(col.Name) { - continue - } - if len(columnMap) > 0 && !columnMap.contain(col.Name) { - continue - } - - if col.MapType == core.ONLYFROMDB { - continue - } - - if statement.incrColumns.isColExist(col.Name) { - continue - } else if statement.decrColumns.isColExist(col.Name) { - continue - } else if statement.exprColumns.isColExist(col.Name) { - continue - } - - fieldValuePtr, err := col.ValueOf(bean) - if err != nil { - engine.logger.Error(err) - continue - } - - fieldValue := *fieldValuePtr - fieldType := reflect.TypeOf(fieldValue.Interface()) - if fieldType == nil { - continue - } - - requiredField := useAllCols - includeNil := useAllCols - - if b, ok := getFlagForColumn(mustColumnMap, col); ok { - if b { - requiredField = true - } else { - continue - } - } - - // !evalphobia! set fieldValue as nil when column is nullable and zero-value - if b, ok := getFlagForColumn(nullableMap, col); ok { - if b && col.Nullable && isZero(fieldValue.Interface()) { - var nilValue *int - fieldValue = reflect.ValueOf(nilValue) - fieldType = reflect.TypeOf(fieldValue.Interface()) - includeNil = true - } - } - - var val interface{} - - if fieldValue.CanAddr() { - if structConvert, ok := fieldValue.Addr().Interface().(core.Conversion); ok { - data, err := structConvert.ToDB() - if err != nil { - engine.logger.Error(err) - } else { - val = data - } - goto APPEND - } - } - - if structConvert, ok := fieldValue.Interface().(core.Conversion); ok { - data, err := structConvert.ToDB() - if err != nil { - engine.logger.Error(err) - } else { - val = data - } - goto APPEND - } - - if fieldType.Kind() == reflect.Ptr { - if fieldValue.IsNil() { - if includeNil { - args = append(args, nil) - colNames = append(colNames, fmt.Sprintf("%v=?", engine.Quote(col.Name))) - } - continue - } else if !fieldValue.IsValid() { - continue - } else { - // dereference ptr type to instance type - fieldValue = fieldValue.Elem() - fieldType = reflect.TypeOf(fieldValue.Interface()) - requiredField = true - } - } - - switch fieldType.Kind() { - case reflect.Bool: - if allUseBool || requiredField { - val = fieldValue.Interface() - } else { - // if a bool in a struct, it will not be as a condition because it default is false, - // please use Where() instead - continue - } - case reflect.String: - if !requiredField && fieldValue.String() == "" { - continue - } - // for MyString, should convert to string or panic - if fieldType.String() != reflect.String.String() { - val = fieldValue.String() - } else { - val = fieldValue.Interface() - } - case reflect.Int8, reflect.Int16, reflect.Int, reflect.Int32, reflect.Int64: - if !requiredField && fieldValue.Int() == 0 { - continue - } - val = fieldValue.Interface() - case reflect.Float32, reflect.Float64: - if !requiredField && fieldValue.Float() == 0.0 { - continue - } - val = fieldValue.Interface() - case reflect.Uint8, reflect.Uint16, reflect.Uint, reflect.Uint32, reflect.Uint64: - if !requiredField && fieldValue.Uint() == 0 { - continue - } - t := int64(fieldValue.Uint()) - val = reflect.ValueOf(&t).Interface() - case reflect.Struct: - if fieldType.ConvertibleTo(core.TimeType) { - t := fieldValue.Convert(core.TimeType).Interface().(time.Time) - if !requiredField && (t.IsZero() || !fieldValue.IsValid()) { - continue - } - val = engine.formatColTime(col, t) - } else if nulType, ok := fieldValue.Interface().(driver.Valuer); ok { - val, _ = nulType.Value() - } else { - if !col.SQLType.IsJson() { - engine.autoMapType(fieldValue) - if table, ok := engine.Tables[fieldValue.Type()]; ok { - if len(table.PrimaryKeys) == 1 { - pkField := reflect.Indirect(fieldValue).FieldByName(table.PKColumns()[0].FieldName) - // fix non-int pk issues - if pkField.IsValid() && (!requiredField && !isZero(pkField.Interface())) { - val = pkField.Interface() - } else { - continue - } - } else { - // TODO: how to handler? - panic("not supported") - } - } else { - val = fieldValue.Interface() - } - } else { - // Blank struct could not be as update data - if requiredField || !isStructZero(fieldValue) { - bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - panic(fmt.Sprintf("mashal %v failed", fieldValue.Interface())) - } - if col.SQLType.IsText() { - val = string(bytes) - } else if col.SQLType.IsBlob() { - val = bytes - } - } else { - continue - } - } - } - case reflect.Array, reflect.Slice, reflect.Map: - if !requiredField { - if fieldValue == reflect.Zero(fieldType) { - continue - } - if fieldType.Kind() == reflect.Array { - if isArrayValueZero(fieldValue) { - continue - } - } else if fieldValue.IsNil() || !fieldValue.IsValid() || fieldValue.Len() == 0 { - continue - } - } - - if col.SQLType.IsText() { - bytes, err := DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - engine.logger.Error(err) - continue - } - val = string(bytes) - } else if col.SQLType.IsBlob() { - var bytes []byte - var err error - if fieldType.Kind() == reflect.Slice && - fieldType.Elem().Kind() == reflect.Uint8 { - if fieldValue.Len() > 0 { - val = fieldValue.Bytes() - } else { - continue - } - } else if fieldType.Kind() == reflect.Array && - fieldType.Elem().Kind() == reflect.Uint8 { - val = fieldValue.Slice(0, 0).Interface() - } else { - bytes, err = DefaultJSONHandler.Marshal(fieldValue.Interface()) - if err != nil { - engine.logger.Error(err) - continue - } - val = bytes - } - } else { - continue - } - default: - val = fieldValue.Interface() - } - - APPEND: - args = append(args, val) - if col.IsPrimaryKey && engine.dialect.DBType() == "ql" { - continue - } - colNames = append(colNames, fmt.Sprintf("%v = ?", engine.Quote(col.Name))) - } - - return colNames, args -} - -func (statement *Statement) needTableName() bool { - return len(statement.JoinStr) > 0 -} - -func (statement *Statement) colName(col *core.Column, tableName string) string { - if statement.needTableName() { - var nm = tableName - if len(statement.TableAlias) > 0 { - nm = statement.TableAlias - } - return statement.Engine.Quote(nm) + "." + statement.Engine.Quote(col.Name) - } - return statement.Engine.Quote(col.Name) -} - -// TableName return current tableName -func (statement *Statement) TableName() string { - if statement.AltTableName != "" { - return statement.AltTableName - } - - return statement.tableName -} - -// ID generate "where id = ? " statement or for composite key "where key1 = ? and key2 = ?" -func (statement *Statement) ID(id interface{}) *Statement { - idValue := reflect.ValueOf(id) - idType := reflect.TypeOf(idValue.Interface()) - - switch idType { - case ptrPkType: - if pkPtr, ok := (id).(*core.PK); ok { - statement.idParam = pkPtr - return statement - } - case pkType: - if pk, ok := (id).(core.PK); ok { - statement.idParam = &pk - return statement - } - } - - switch idType.Kind() { - case reflect.String: - statement.idParam = &core.PK{idValue.Convert(reflect.TypeOf("")).Interface()} - return statement - } - - statement.idParam = &core.PK{id} - return statement -} - -// Incr Generate "Update ... Set column = column + arg" statement -func (statement *Statement) Incr(column string, arg ...interface{}) *Statement { - if len(arg) > 0 { - statement.incrColumns.addParam(column, arg[0]) - } else { - statement.incrColumns.addParam(column, 1) - } - return statement -} - -// Decr Generate "Update ... Set column = column - arg" statement -func (statement *Statement) Decr(column string, arg ...interface{}) *Statement { - if len(arg) > 0 { - statement.decrColumns.addParam(column, arg[0]) - } else { - statement.decrColumns.addParam(column, 1) - } - return statement -} - -// SetExpr Generate "Update ... Set column = {expression}" statement -func (statement *Statement) SetExpr(column string, expression interface{}) *Statement { - statement.exprColumns.addParam(column, expression) - return statement -} - -func (statement *Statement) col2NewColsWithQuote(columns ...string) []string { - newColumns := make([]string, 0) - quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`") - for _, col := range columns { - newColumns = append(newColumns, statement.Engine.Quote(eraseAny(col, quotes...))) - } - return newColumns -} - -func (statement *Statement) colmap2NewColsWithQuote() []string { - newColumns := make([]string, len(statement.columnMap), len(statement.columnMap)) - copy(newColumns, statement.columnMap) - for i := 0; i < len(statement.columnMap); i++ { - newColumns[i] = statement.Engine.Quote(newColumns[i]) - } - return newColumns -} - -// Distinct generates "DISTINCT col1, col2 " statement -func (statement *Statement) Distinct(columns ...string) *Statement { - statement.IsDistinct = true - statement.Cols(columns...) - return statement -} - -// ForUpdate generates "SELECT ... FOR UPDATE" statement -func (statement *Statement) ForUpdate() *Statement { - statement.IsForUpdate = true - return statement -} - -// Select replace select -func (statement *Statement) Select(str string) *Statement { - statement.selectStr = str - return statement -} - -// Cols generate "col1, col2" statement -func (statement *Statement) Cols(columns ...string) *Statement { - cols := col2NewCols(columns...) - for _, nc := range cols { - statement.columnMap.add(nc) - } - - newColumns := statement.colmap2NewColsWithQuote() - - statement.ColumnStr = strings.Join(newColumns, ", ") - statement.ColumnStr = strings.Replace(statement.ColumnStr, statement.Engine.quote("*"), "*", -1) - return statement -} - -// AllCols update use only: update all columns -func (statement *Statement) AllCols() *Statement { - statement.useAllCols = true - return statement -} - -// MustCols update use only: must update columns -func (statement *Statement) MustCols(columns ...string) *Statement { - newColumns := col2NewCols(columns...) - for _, nc := range newColumns { - statement.mustColumnMap[strings.ToLower(nc)] = true - } - return statement -} - -// UseBool indicates that use bool fields as update contents and query contiditions -func (statement *Statement) UseBool(columns ...string) *Statement { - if len(columns) > 0 { - statement.MustCols(columns...) - } else { - statement.allUseBool = true - } - return statement -} - -// Omit do not use the columns -func (statement *Statement) Omit(columns ...string) { - newColumns := col2NewCols(columns...) - for _, nc := range newColumns { - statement.omitColumnMap = append(statement.omitColumnMap, nc) - } - statement.OmitStr = statement.Engine.Quote(strings.Join(newColumns, statement.Engine.Quote(", "))) -} - -// Nullable Update use only: update columns to null when value is nullable and zero-value -func (statement *Statement) Nullable(columns ...string) { - newColumns := col2NewCols(columns...) - for _, nc := range newColumns { - statement.nullableMap[strings.ToLower(nc)] = true - } -} - -// Top generate LIMIT limit statement -func (statement *Statement) Top(limit int) *Statement { - statement.Limit(limit) - return statement -} - -// Limit generate LIMIT start, limit statement -func (statement *Statement) Limit(limit int, start ...int) *Statement { - statement.LimitN = limit - if len(start) > 0 { - statement.Start = start[0] - } - return statement -} - -// OrderBy generate "Order By order" statement -func (statement *Statement) OrderBy(order string) *Statement { - if len(statement.OrderStr) > 0 { - statement.OrderStr += ", " - } - statement.OrderStr += order - return statement -} - -// Desc generate `ORDER BY xx DESC` -func (statement *Statement) Desc(colNames ...string) *Statement { - var buf strings.Builder - if len(statement.OrderStr) > 0 { - fmt.Fprint(&buf, statement.OrderStr, ", ") - } - newColNames := statement.col2NewColsWithQuote(colNames...) - fmt.Fprintf(&buf, "%v DESC", strings.Join(newColNames, " DESC, ")) - statement.OrderStr = buf.String() - return statement -} - -// Asc provide asc order by query condition, the input parameters are columns. -func (statement *Statement) Asc(colNames ...string) *Statement { - var buf strings.Builder - if len(statement.OrderStr) > 0 { - fmt.Fprint(&buf, statement.OrderStr, ", ") - } - newColNames := statement.col2NewColsWithQuote(colNames...) - fmt.Fprintf(&buf, "%v ASC", strings.Join(newColNames, " ASC, ")) - statement.OrderStr = buf.String() - return statement -} - -// Table tempororily set table name, the parameter could be a string or a pointer of struct -func (statement *Statement) Table(tableNameOrBean interface{}) *Statement { - v := rValue(tableNameOrBean) - t := v.Type() - if t.Kind() == reflect.Struct { - var err error - statement.RefTable, err = statement.Engine.autoMapType(v) - if err != nil { - statement.Engine.logger.Error(err) - return statement - } - } - - statement.AltTableName = statement.Engine.TableName(tableNameOrBean, true) - return statement -} - -// Join The joinOP should be one of INNER, LEFT OUTER, CROSS etc - this will be prepended to JOIN -func (statement *Statement) Join(joinOP string, tablename interface{}, condition string, args ...interface{}) *Statement { - var buf strings.Builder - if len(statement.JoinStr) > 0 { - fmt.Fprintf(&buf, "%v %v JOIN ", statement.JoinStr, joinOP) - } else { - fmt.Fprintf(&buf, "%v JOIN ", joinOP) - } - - switch tp := tablename.(type) { - case builder.Builder: - subSQL, subQueryArgs, err := tp.ToSQL() - if err != nil { - statement.lastError = err - return statement - } - tbs := strings.Split(tp.TableName(), ".") - quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`") - - var aliasName = strings.Trim(tbs[len(tbs)-1], strings.Join(quotes, "")) - fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition) - statement.joinArgs = append(statement.joinArgs, subQueryArgs...) - case *builder.Builder: - subSQL, subQueryArgs, err := tp.ToSQL() - if err != nil { - statement.lastError = err - return statement - } - tbs := strings.Split(tp.TableName(), ".") - quotes := append(strings.Split(statement.Engine.Quote(""), ""), "`") - - var aliasName = strings.Trim(tbs[len(tbs)-1], strings.Join(quotes, "")) - fmt.Fprintf(&buf, "(%s) %s ON %v", subSQL, aliasName, condition) - statement.joinArgs = append(statement.joinArgs, subQueryArgs...) - default: - tbName := statement.Engine.TableName(tablename, true) - fmt.Fprintf(&buf, "%s ON %v", tbName, condition) - } - - statement.JoinStr = buf.String() - statement.joinArgs = append(statement.joinArgs, args...) - return statement -} - -// GroupBy generate "Group By keys" statement -func (statement *Statement) GroupBy(keys string) *Statement { - statement.GroupByStr = keys - return statement -} - -// Having generate "Having conditions" statement -func (statement *Statement) Having(conditions string) *Statement { - statement.HavingStr = fmt.Sprintf("HAVING %v", conditions) - return statement -} - -// Unscoped always disable struct tag "deleted" -func (statement *Statement) Unscoped() *Statement { - statement.unscoped = true - return statement -} - -func (statement *Statement) genColumnStr() string { - if statement.RefTable == nil { - return "" - } - - var buf strings.Builder - columns := statement.RefTable.Columns() - - for _, col := range columns { - if statement.omitColumnMap.contain(col.Name) { - continue - } - - if len(statement.columnMap) > 0 && !statement.columnMap.contain(col.Name) { - continue - } - - if col.MapType == core.ONLYTODB { - continue - } - - if buf.Len() != 0 { - buf.WriteString(", ") - } - - if statement.JoinStr != "" { - if statement.TableAlias != "" { - buf.WriteString(statement.TableAlias) - } else { - buf.WriteString(statement.TableName()) - } - - buf.WriteString(".") - } - - statement.Engine.QuoteTo(&buf, col.Name) - } - - return buf.String() -} - -func (statement *Statement) genCreateTableSQL() string { - return statement.Engine.dialect.CreateTableSql(statement.RefTable, statement.TableName(), - statement.StoreEngine, statement.Charset) -} - -func (statement *Statement) genIndexSQL() []string { - var sqls []string - tbName := statement.TableName() - for _, index := range statement.RefTable.Indexes { - if index.Type == core.IndexType { - sql := statement.Engine.dialect.CreateIndexSql(tbName, index) - /*idxTBName := strings.Replace(tbName, ".", "_", -1) - idxTBName = strings.Replace(idxTBName, `"`, "", -1) - sql := fmt.Sprintf("CREATE INDEX %v ON %v (%v);", quote(indexName(idxTBName, idxName)), - quote(tbName), quote(strings.Join(index.Cols, quote(","))))*/ - sqls = append(sqls, sql) - } - } - return sqls -} - -func uniqueName(tableName, uqeName string) string { - return fmt.Sprintf("UQE_%v_%v", tableName, uqeName) -} - -func (statement *Statement) genUniqueSQL() []string { - var sqls []string - tbName := statement.TableName() - for _, index := range statement.RefTable.Indexes { - if index.Type == core.UniqueType { - sql := statement.Engine.dialect.CreateIndexSql(tbName, index) - sqls = append(sqls, sql) - } - } - return sqls -} - -func (statement *Statement) genDelIndexSQL() []string { - var sqls []string - tbName := statement.TableName() - idxPrefixName := strings.Replace(tbName, `"`, "", -1) - idxPrefixName = strings.Replace(idxPrefixName, `.`, "_", -1) - for idxName, index := range statement.RefTable.Indexes { - var rIdxName string - if index.Type == core.UniqueType { - rIdxName = uniqueName(idxPrefixName, idxName) - } else if index.Type == core.IndexType { - rIdxName = indexName(idxPrefixName, idxName) - } - sql := fmt.Sprintf("DROP INDEX %v", statement.Engine.Quote(statement.Engine.TableName(rIdxName, true))) - if statement.Engine.dialect.IndexOnTable() { - sql += fmt.Sprintf(" ON %v", statement.Engine.Quote(tbName)) - } - sqls = append(sqls, sql) - } - return sqls -} - -func (statement *Statement) genAddColumnStr(col *core.Column) (string, []interface{}) { - quote := statement.Engine.Quote - sql := fmt.Sprintf("ALTER TABLE %v ADD %v", quote(statement.TableName()), - col.String(statement.Engine.dialect)) - if statement.Engine.dialect.DBType() == core.MYSQL && len(col.Comment) > 0 { - sql += " COMMENT '" + col.Comment + "'" - } - sql += ";" - return sql, []interface{}{} -} - -func (statement *Statement) buildConds(table *core.Table, bean interface{}, includeVersion bool, includeUpdated bool, includeNil bool, includeAutoIncr bool, addedTableName bool) (builder.Cond, error) { - return statement.Engine.buildConds(table, bean, includeVersion, includeUpdated, includeNil, includeAutoIncr, statement.allUseBool, statement.useAllCols, - statement.unscoped, statement.mustColumnMap, statement.TableName(), statement.TableAlias, addedTableName) -} - -func (statement *Statement) mergeConds(bean interface{}) error { - if !statement.noAutoCondition { - var addedTableName = (len(statement.JoinStr) > 0) - autoCond, err := statement.buildConds(statement.RefTable, bean, true, true, false, true, addedTableName) - if err != nil { - return err - } - statement.cond = statement.cond.And(autoCond) - } - - if err := statement.processIDParam(); err != nil { - return err - } - return nil -} - -func (statement *Statement) genConds(bean interface{}) (string, []interface{}, error) { - if err := statement.mergeConds(bean); err != nil { - return "", nil, err - } - - return builder.ToSQL(statement.cond) -} - -func (statement *Statement) genGetSQL(bean interface{}) (string, []interface{}, error) { - v := rValue(bean) - isStruct := v.Kind() == reflect.Struct - if isStruct { - statement.setRefBean(bean) - } - - var columnStr = statement.ColumnStr - if len(statement.selectStr) > 0 { - columnStr = statement.selectStr - } else { - // TODO: always generate column names, not use * even if join - if len(statement.JoinStr) == 0 { - if len(columnStr) == 0 { - if len(statement.GroupByStr) > 0 { - columnStr = statement.Engine.quoteColumns(statement.GroupByStr) - } else { - columnStr = statement.genColumnStr() - } - } - } else { - if len(columnStr) == 0 { - if len(statement.GroupByStr) > 0 { - columnStr = statement.Engine.quoteColumns(statement.GroupByStr) - } - } - } - } - - if len(columnStr) == 0 { - columnStr = "*" - } - - if isStruct { - if err := statement.mergeConds(bean); err != nil { - return "", nil, err - } - } else { - if err := statement.processIDParam(); err != nil { - return "", nil, err - } - } - condSQL, condArgs, err := builder.ToSQL(statement.cond) - if err != nil { - return "", nil, err - } - - sqlStr, err := statement.genSelectSQL(columnStr, condSQL, true, true) - if err != nil { - return "", nil, err - } - - return sqlStr, append(statement.joinArgs, condArgs...), nil -} - -func (statement *Statement) genCountSQL(beans ...interface{}) (string, []interface{}, error) { - var condSQL string - var condArgs []interface{} - var err error - if len(beans) > 0 { - statement.setRefBean(beans[0]) - condSQL, condArgs, err = statement.genConds(beans[0]) - } else { - condSQL, condArgs, err = builder.ToSQL(statement.cond) - } - if err != nil { - return "", nil, err - } - - var selectSQL = statement.selectStr - if len(selectSQL) <= 0 { - if statement.IsDistinct { - selectSQL = fmt.Sprintf("count(DISTINCT %s)", statement.ColumnStr) - } else { - selectSQL = "count(*)" - } - } - sqlStr, err := statement.genSelectSQL(selectSQL, condSQL, false, false) - if err != nil { - return "", nil, err - } - - return sqlStr, append(statement.joinArgs, condArgs...), nil -} - -func (statement *Statement) genSumSQL(bean interface{}, columns ...string) (string, []interface{}, error) { - statement.setRefBean(bean) - - var sumStrs = make([]string, 0, len(columns)) - for _, colName := range columns { - if !strings.Contains(colName, " ") && !strings.Contains(colName, "(") { - colName = statement.Engine.Quote(colName) - } - sumStrs = append(sumStrs, fmt.Sprintf("COALESCE(sum(%s),0)", colName)) - } - sumSelect := strings.Join(sumStrs, ", ") - - condSQL, condArgs, err := statement.genConds(bean) - if err != nil { - return "", nil, err - } - - sqlStr, err := statement.genSelectSQL(sumSelect, condSQL, true, true) - if err != nil { - return "", nil, err - } - - return sqlStr, append(statement.joinArgs, condArgs...), nil -} - -func (statement *Statement) genSelectSQL(columnStr, condSQL string, needLimit, needOrderBy bool) (string, error) { - var ( - distinct string - dialect = statement.Engine.Dialect() - quote = statement.Engine.Quote - fromStr = " FROM " - top, mssqlCondi, whereStr string - ) - if statement.IsDistinct && !strings.HasPrefix(columnStr, "count") { - distinct = "DISTINCT " - } - if len(condSQL) > 0 { - whereStr = " WHERE " + condSQL - } - - if dialect.DBType() == core.MSSQL && strings.Contains(statement.TableName(), "..") { - fromStr += statement.TableName() - } else { - fromStr += quote(statement.TableName()) - } - - if statement.TableAlias != "" { - if dialect.DBType() == core.ORACLE { - fromStr += " " + quote(statement.TableAlias) - } else { - fromStr += " AS " + quote(statement.TableAlias) - } - } - if statement.JoinStr != "" { - fromStr = fmt.Sprintf("%v %v", fromStr, statement.JoinStr) - } - - if dialect.DBType() == core.MSSQL { - if statement.LimitN > 0 { - top = fmt.Sprintf("TOP %d ", statement.LimitN) - } - if statement.Start > 0 { - var column string - if len(statement.RefTable.PKColumns()) == 0 { - for _, index := range statement.RefTable.Indexes { - if len(index.Cols) == 1 { - column = index.Cols[0] - break - } - } - if len(column) == 0 { - column = statement.RefTable.ColumnsSeq()[0] - } - } else { - column = statement.RefTable.PKColumns()[0].Name - } - if statement.needTableName() { - if len(statement.TableAlias) > 0 { - column = statement.TableAlias + "." + column - } else { - column = statement.TableName() + "." + column - } - } - - var orderStr string - if needOrderBy && len(statement.OrderStr) > 0 { - orderStr = " ORDER BY " + statement.OrderStr - } - - var groupStr string - if len(statement.GroupByStr) > 0 { - groupStr = " GROUP BY " + statement.GroupByStr - } - mssqlCondi = fmt.Sprintf("(%s NOT IN (SELECT TOP %d %s%s%s%s%s))", - column, statement.Start, column, fromStr, whereStr, orderStr, groupStr) - } - } - - var buf strings.Builder - fmt.Fprintf(&buf, "SELECT %v%v%v%v%v", distinct, top, columnStr, fromStr, whereStr) - if len(mssqlCondi) > 0 { - if len(whereStr) > 0 { - fmt.Fprint(&buf, " AND ", mssqlCondi) - } else { - fmt.Fprint(&buf, " WHERE ", mssqlCondi) - } - } - - if statement.GroupByStr != "" { - fmt.Fprint(&buf, " GROUP BY ", statement.GroupByStr) - } - if statement.HavingStr != "" { - fmt.Fprint(&buf, " ", statement.HavingStr) - } - if needOrderBy && statement.OrderStr != "" { - fmt.Fprint(&buf, " ORDER BY ", statement.OrderStr) - } - if needLimit { - if dialect.DBType() != core.MSSQL && dialect.DBType() != core.ORACLE { - if statement.Start > 0 { - fmt.Fprintf(&buf, " LIMIT %v OFFSET %v", statement.LimitN, statement.Start) - } else if statement.LimitN > 0 { - fmt.Fprint(&buf, " LIMIT ", statement.LimitN) - } - } else if dialect.DBType() == core.ORACLE { - if statement.Start != 0 || statement.LimitN != 0 { - oldString := buf.String() - buf.Reset() - rawColStr := columnStr - if rawColStr == "*" { - rawColStr = "at.*" - } - fmt.Fprintf(&buf, "SELECT %v FROM (SELECT %v,ROWNUM RN FROM (%v) at WHERE ROWNUM <= %d) aat WHERE RN > %d", - columnStr, rawColStr, oldString, statement.Start+statement.LimitN, statement.Start) - } - } - } - if statement.IsForUpdate { - return dialect.ForUpdateSql(buf.String()), nil - } - - return buf.String(), nil -} - -func (statement *Statement) processIDParam() error { - if statement.idParam == nil || statement.RefTable == nil { - return nil - } - - if len(statement.RefTable.PrimaryKeys) != len(*statement.idParam) { - return fmt.Errorf("ID condition is error, expect %d primarykeys, there are %d", - len(statement.RefTable.PrimaryKeys), - len(*statement.idParam), - ) - } - - for i, col := range statement.RefTable.PKColumns() { - var colName = statement.colName(col, statement.TableName()) - statement.cond = statement.cond.And(builder.Eq{colName: (*(statement.idParam))[i]}) - } - return nil -} - -func (statement *Statement) joinColumns(cols []*core.Column, includeTableName bool) string { - var colnames = make([]string, len(cols)) - for i, col := range cols { - if includeTableName { - colnames[i] = statement.Engine.Quote(statement.TableName()) + - "." + statement.Engine.Quote(col.Name) - } else { - colnames[i] = statement.Engine.Quote(col.Name) - } - } - return strings.Join(colnames, ", ") -} - -func (statement *Statement) convertIDSQL(sqlStr string) string { - if statement.RefTable != nil { - cols := statement.RefTable.PKColumns() - if len(cols) == 0 { - return "" - } - - colstrs := statement.joinColumns(cols, false) - sqls := splitNNoCase(sqlStr, " from ", 2) - if len(sqls) != 2 { - return "" - } - - var top string - if statement.LimitN > 0 && statement.Engine.dialect.DBType() == core.MSSQL { - top = fmt.Sprintf("TOP %d ", statement.LimitN) - } - - newsql := fmt.Sprintf("SELECT %s%s FROM %v", top, colstrs, sqls[1]) - return newsql - } - return "" -} - -func (statement *Statement) convertUpdateSQL(sqlStr string) (string, string) { - if statement.RefTable == nil || len(statement.RefTable.PrimaryKeys) != 1 { - return "", "" - } - - colstrs := statement.joinColumns(statement.RefTable.PKColumns(), true) - sqls := splitNNoCase(sqlStr, "where", 2) - if len(sqls) != 2 { - if len(sqls) == 1 { - return sqls[0], fmt.Sprintf("SELECT %v FROM %v", - colstrs, statement.Engine.Quote(statement.TableName())) - } - return "", "" - } - - var whereStr = sqls[1] - - // TODO: for postgres only, if any other database? - var paraStr string - if statement.Engine.dialect.DBType() == core.POSTGRES { - paraStr = "$" - } else if statement.Engine.dialect.DBType() == core.MSSQL { - paraStr = ":" - } - - if paraStr != "" { - if strings.Contains(sqls[1], paraStr) { - dollers := strings.Split(sqls[1], paraStr) - whereStr = dollers[0] - for i, c := range dollers[1:] { - ccs := strings.SplitN(c, " ", 2) - whereStr += fmt.Sprintf(paraStr+"%v %v", i+1, ccs[1]) - } - } - } - - return sqls[0], fmt.Sprintf("SELECT %v FROM %v WHERE %v", - colstrs, statement.Engine.Quote(statement.TableName()), - whereStr) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_args.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_args.go deleted file mode 100644 index 310f24d6b..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_args.go +++ /dev/null @@ -1,170 +0,0 @@ -// Copyright 2019 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "reflect" - "strings" - "time" - - "xorm.io/builder" - "xorm.io/core" -) - -func quoteNeeded(a interface{}) bool { - switch a.(type) { - case int, int8, int16, int32, int64: - return false - case uint, uint8, uint16, uint32, uint64: - return false - case float32, float64: - return false - case bool: - return false - case string: - return true - case time.Time, *time.Time: - return true - case builder.Builder, *builder.Builder: - return false - } - - t := reflect.TypeOf(a) - switch t.Kind() { - case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: - return false - case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64: - return false - case reflect.Float32, reflect.Float64: - return false - case reflect.Bool: - return false - case reflect.String: - return true - } - - return true -} - -func convertStringSingleQuote(arg string) string { - return "'" + strings.Replace(arg, "'", "''", -1) + "'" -} - -func convertString(arg string) string { - var buf strings.Builder - buf.WriteRune('\'') - for _, c := range arg { - if c == '\\' || c == '\'' { - buf.WriteRune('\\') - } - buf.WriteRune(c) - } - buf.WriteRune('\'') - return buf.String() -} - -func convertArg(arg interface{}, convertFunc func(string) string) string { - if quoteNeeded(arg) { - argv := fmt.Sprintf("%v", arg) - return convertFunc(argv) - } - - return fmt.Sprintf("%v", arg) -} - -const insertSelectPlaceHolder = true - -func (statement *Statement) writeArg(w *builder.BytesWriter, arg interface{}) error { - switch argv := arg.(type) { - case bool: - if statement.Engine.dialect.DBType() == core.MSSQL { - if argv { - if _, err := w.WriteString("1"); err != nil { - return err - } - } else { - if _, err := w.WriteString("0"); err != nil { - return err - } - } - } else { - if argv { - if _, err := w.WriteString("true"); err != nil { - return err - } - } else { - if _, err := w.WriteString("false"); err != nil { - return err - } - } - } - case *builder.Builder: - if _, err := w.WriteString("("); err != nil { - return err - } - if err := argv.WriteTo(w); err != nil { - return err - } - if _, err := w.WriteString(")"); err != nil { - return err - } - default: - if insertSelectPlaceHolder { - if err := w.WriteByte('?'); err != nil { - return err - } - w.Append(arg) - } else { - var convertFunc = convertStringSingleQuote - if statement.Engine.dialect.DBType() == core.MYSQL { - convertFunc = convertString - } - if _, err := w.WriteString(convertArg(arg, convertFunc)); err != nil { - return err - } - } - } - return nil -} - -func (statement *Statement) writeArgs(w *builder.BytesWriter, args []interface{}) error { - for i, arg := range args { - if err := statement.writeArg(w, arg); err != nil { - return err - } - - if i+1 != len(args) { - if _, err := w.WriteString(","); err != nil { - return err - } - } - } - return nil -} - -func writeStrings(w *builder.BytesWriter, cols []string, leftQuote, rightQuote string) error { - for i, colName := range cols { - if len(leftQuote) > 0 && colName[0] != '`' { - if _, err := w.WriteString(leftQuote); err != nil { - return err - } - } - if _, err := w.WriteString(colName); err != nil { - return err - } - if len(rightQuote) > 0 && colName[len(colName)-1] != '`' { - if _, err := w.WriteString(rightQuote); err != nil { - return err - } - } - if i+1 != len(cols) { - if _, err := w.WriteString(","); err != nil { - return err - } - } - } - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_columnmap.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_columnmap.go deleted file mode 100644 index b6523b1e7..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_columnmap.go +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright 2019 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import "strings" - -type columnMap []string - -func (m columnMap) contain(colName string) bool { - if len(m) == 0 { - return false - } - - n := len(colName) - for _, mk := range m { - if len(mk) != n { - continue - } - if strings.EqualFold(mk, colName) { - return true - } - } - - return false -} - -func (m *columnMap) add(colName string) bool { - if m.contain(colName) { - return false - } - *m = append(*m, colName) - return true -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_exprparam.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_exprparam.go deleted file mode 100644 index 4da4f1ea1..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_exprparam.go +++ /dev/null @@ -1,117 +0,0 @@ -// Copyright 2019 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "strings" - - "xorm.io/builder" -) - -type ErrUnsupportedExprType struct { - tp string -} - -func (err ErrUnsupportedExprType) Error() string { - return fmt.Sprintf("Unsupported expression type: %v", err.tp) -} - -type exprParam struct { - colName string - arg interface{} -} - -type exprParams struct { - colNames []string - args []interface{} -} - -func (exprs *exprParams) Len() int { - return len(exprs.colNames) -} - -func (exprs *exprParams) addParam(colName string, arg interface{}) { - exprs.colNames = append(exprs.colNames, colName) - exprs.args = append(exprs.args, arg) -} - -func (exprs *exprParams) isColExist(colName string) bool { - for _, name := range exprs.colNames { - if strings.EqualFold(trimQuote(name), trimQuote(colName)) { - return true - } - } - return false -} - -func (exprs *exprParams) getByName(colName string) (exprParam, bool) { - for i, name := range exprs.colNames { - if strings.EqualFold(name, colName) { - return exprParam{name, exprs.args[i]}, true - } - } - return exprParam{}, false -} - -func (exprs *exprParams) writeArgs(w *builder.BytesWriter) error { - for i, expr := range exprs.args { - switch arg := expr.(type) { - case *builder.Builder: - if _, err := w.WriteString("("); err != nil { - return err - } - if err := arg.WriteTo(w); err != nil { - return err - } - if _, err := w.WriteString(")"); err != nil { - return err - } - default: - if _, err := w.WriteString(fmt.Sprintf("%v", arg)); err != nil { - return err - } - } - if i != len(exprs.args)-1 { - if _, err := w.WriteString(","); err != nil { - return err - } - } - } - return nil -} - -func (exprs *exprParams) writeNameArgs(w *builder.BytesWriter) error { - for i, colName := range exprs.colNames { - if _, err := w.WriteString(colName); err != nil { - return err - } - if _, err := w.WriteString("="); err != nil { - return err - } - - switch arg := exprs.args[i].(type) { - case *builder.Builder: - if _, err := w.WriteString("("); err != nil { - return err - } - if err := arg.WriteTo(w); err != nil { - return err - } - if _, err := w.WriteString("("); err != nil { - return err - } - default: - w.Append(exprs.args[i]) - } - - if i+1 != len(exprs.colNames) { - if _, err := w.WriteString(","); err != nil { - return err - } - } - } - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_quote.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_quote.go deleted file mode 100644 index e22e0d147..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/statement_quote.go +++ /dev/null @@ -1,19 +0,0 @@ -// Copyright 2019 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -func trimQuote(s string) string { - if len(s) == 0 { - return s - } - - if s[0] == '`' { - s = s[1:] - } - if len(s) > 0 && s[len(s)-1] == '`' { - return s[:len(s)-1] - } - return s -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/syslogger.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/syslogger.go deleted file mode 100644 index 11ba01e7b..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/syslogger.go +++ /dev/null @@ -1,89 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build !windows,!nacl,!plan9 - -package xorm - -import ( - "fmt" - "log/syslog" - - "xorm.io/core" -) - -var _ core.ILogger = &SyslogLogger{} - -// SyslogLogger will be depricated -type SyslogLogger struct { - w *syslog.Writer - showSQL bool -} - -// NewSyslogLogger implements core.ILogger -func NewSyslogLogger(w *syslog.Writer) *SyslogLogger { - return &SyslogLogger{w: w} -} - -// Debug log content as Debug -func (s *SyslogLogger) Debug(v ...interface{}) { - s.w.Debug(fmt.Sprint(v...)) -} - -// Debugf log content as Debug and format -func (s *SyslogLogger) Debugf(format string, v ...interface{}) { - s.w.Debug(fmt.Sprintf(format, v...)) -} - -// Error log content as Error -func (s *SyslogLogger) Error(v ...interface{}) { - s.w.Err(fmt.Sprint(v...)) -} - -// Errorf log content as Errorf and format -func (s *SyslogLogger) Errorf(format string, v ...interface{}) { - s.w.Err(fmt.Sprintf(format, v...)) -} - -// Info log content as Info -func (s *SyslogLogger) Info(v ...interface{}) { - s.w.Info(fmt.Sprint(v...)) -} - -// Infof log content as Infof and format -func (s *SyslogLogger) Infof(format string, v ...interface{}) { - s.w.Info(fmt.Sprintf(format, v...)) -} - -// Warn log content as Warn -func (s *SyslogLogger) Warn(v ...interface{}) { - s.w.Warning(fmt.Sprint(v...)) -} - -// Warnf log content as Warnf and format -func (s *SyslogLogger) Warnf(format string, v ...interface{}) { - s.w.Warning(fmt.Sprintf(format, v...)) -} - -// Level shows log level -func (s *SyslogLogger) Level() core.LogLevel { - return core.LOG_UNKNOWN -} - -// SetLevel always return error, as current log/syslog package doesn't allow to set priority level after syslog.Writer created -func (s *SyslogLogger) SetLevel(l core.LogLevel) {} - -// ShowSQL set if logging SQL -func (s *SyslogLogger) ShowSQL(show ...bool) { - if len(show) == 0 { - s.showSQL = true - return - } - s.showSQL = show[0] -} - -// IsShowSQL if logging SQL -func (s *SyslogLogger) IsShowSQL() bool { - return s.showSQL -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/tag.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/tag.go deleted file mode 100644 index ec8d5cf05..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/tag.go +++ /dev/null @@ -1,311 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "reflect" - "strconv" - "strings" - "time" - - "xorm.io/core" -) - -type tagContext struct { - tagName string - params []string - preTag, nextTag string - table *core.Table - col *core.Column - fieldValue reflect.Value - isIndex bool - isUnique bool - indexNames map[string]int - engine *Engine - hasCacheTag bool - hasNoCacheTag bool - ignoreNext bool -} - -// tagHandler describes tag handler for XORM -type tagHandler func(ctx *tagContext) error - -var ( - // defaultTagHandlers enumerates all the default tag handler - defaultTagHandlers = map[string]tagHandler{ - "<-": OnlyFromDBTagHandler, - "->": OnlyToDBTagHandler, - "PK": PKTagHandler, - "NULL": NULLTagHandler, - "NOT": IgnoreTagHandler, - "AUTOINCR": AutoIncrTagHandler, - "DEFAULT": DefaultTagHandler, - "CREATED": CreatedTagHandler, - "UPDATED": UpdatedTagHandler, - "DELETED": DeletedTagHandler, - "VERSION": VersionTagHandler, - "UTC": UTCTagHandler, - "LOCAL": LocalTagHandler, - "NOTNULL": NotNullTagHandler, - "INDEX": IndexTagHandler, - "UNIQUE": UniqueTagHandler, - "CACHE": CacheTagHandler, - "NOCACHE": NoCacheTagHandler, - "COMMENT": CommentTagHandler, - } -) - -func init() { - for k := range core.SqlTypes { - defaultTagHandlers[k] = SQLTypeTagHandler - } -} - -// IgnoreTagHandler describes ignored tag handler -func IgnoreTagHandler(ctx *tagContext) error { - return nil -} - -// OnlyFromDBTagHandler describes mapping direction tag handler -func OnlyFromDBTagHandler(ctx *tagContext) error { - ctx.col.MapType = core.ONLYFROMDB - return nil -} - -// OnlyToDBTagHandler describes mapping direction tag handler -func OnlyToDBTagHandler(ctx *tagContext) error { - ctx.col.MapType = core.ONLYTODB - return nil -} - -// PKTagHandler decribes primary key tag handler -func PKTagHandler(ctx *tagContext) error { - ctx.col.IsPrimaryKey = true - ctx.col.Nullable = false - return nil -} - -// NULLTagHandler describes null tag handler -func NULLTagHandler(ctx *tagContext) error { - ctx.col.Nullable = (strings.ToUpper(ctx.preTag) != "NOT") - return nil -} - -// NotNullTagHandler describes notnull tag handler -func NotNullTagHandler(ctx *tagContext) error { - ctx.col.Nullable = false - return nil -} - -// AutoIncrTagHandler describes autoincr tag handler -func AutoIncrTagHandler(ctx *tagContext) error { - ctx.col.IsAutoIncrement = true - /* - if len(ctx.params) > 0 { - autoStartInt, err := strconv.Atoi(ctx.params[0]) - if err != nil { - return err - } - ctx.col.AutoIncrStart = autoStartInt - } else { - ctx.col.AutoIncrStart = 1 - } - */ - return nil -} - -// DefaultTagHandler describes default tag handler -func DefaultTagHandler(ctx *tagContext) error { - if len(ctx.params) > 0 { - ctx.col.Default = ctx.params[0] - } else { - ctx.col.Default = ctx.nextTag - ctx.ignoreNext = true - } - ctx.col.DefaultIsEmpty = false - return nil -} - -// CreatedTagHandler describes created tag handler -func CreatedTagHandler(ctx *tagContext) error { - ctx.col.IsCreated = true - return nil -} - -// VersionTagHandler describes version tag handler -func VersionTagHandler(ctx *tagContext) error { - ctx.col.IsVersion = true - ctx.col.Default = "1" - return nil -} - -// UTCTagHandler describes utc tag handler -func UTCTagHandler(ctx *tagContext) error { - ctx.col.TimeZone = time.UTC - return nil -} - -// LocalTagHandler describes local tag handler -func LocalTagHandler(ctx *tagContext) error { - if len(ctx.params) == 0 { - ctx.col.TimeZone = time.Local - } else { - var err error - ctx.col.TimeZone, err = time.LoadLocation(ctx.params[0]) - if err != nil { - return err - } - } - return nil -} - -// UpdatedTagHandler describes updated tag handler -func UpdatedTagHandler(ctx *tagContext) error { - ctx.col.IsUpdated = true - return nil -} - -// DeletedTagHandler describes deleted tag handler -func DeletedTagHandler(ctx *tagContext) error { - ctx.col.IsDeleted = true - return nil -} - -// IndexTagHandler describes index tag handler -func IndexTagHandler(ctx *tagContext) error { - if len(ctx.params) > 0 { - ctx.indexNames[ctx.params[0]] = core.IndexType - } else { - ctx.isIndex = true - } - return nil -} - -// UniqueTagHandler describes unique tag handler -func UniqueTagHandler(ctx *tagContext) error { - if len(ctx.params) > 0 { - ctx.indexNames[ctx.params[0]] = core.UniqueType - } else { - ctx.isUnique = true - } - return nil -} - -// CommentTagHandler add comment to column -func CommentTagHandler(ctx *tagContext) error { - if len(ctx.params) > 0 { - ctx.col.Comment = strings.Trim(ctx.params[0], "' ") - } - return nil -} - -// SQLTypeTagHandler describes SQL Type tag handler -func SQLTypeTagHandler(ctx *tagContext) error { - ctx.col.SQLType = core.SQLType{Name: ctx.tagName} - if len(ctx.params) > 0 { - if ctx.tagName == core.Enum { - ctx.col.EnumOptions = make(map[string]int) - for k, v := range ctx.params { - v = strings.TrimSpace(v) - v = strings.Trim(v, "'") - ctx.col.EnumOptions[v] = k - } - } else if ctx.tagName == core.Set { - ctx.col.SetOptions = make(map[string]int) - for k, v := range ctx.params { - v = strings.TrimSpace(v) - v = strings.Trim(v, "'") - ctx.col.SetOptions[v] = k - } - } else { - var err error - if len(ctx.params) == 2 { - ctx.col.Length, err = strconv.Atoi(ctx.params[0]) - if err != nil { - return err - } - ctx.col.Length2, err = strconv.Atoi(ctx.params[1]) - if err != nil { - return err - } - } else if len(ctx.params) == 1 { - ctx.col.Length, err = strconv.Atoi(ctx.params[0]) - if err != nil { - return err - } - } - } - } - return nil -} - -// ExtendsTagHandler describes extends tag handler -func ExtendsTagHandler(ctx *tagContext) error { - var fieldValue = ctx.fieldValue - var isPtr = false - switch fieldValue.Kind() { - case reflect.Ptr: - f := fieldValue.Type().Elem() - if f.Kind() == reflect.Struct { - fieldPtr := fieldValue - fieldValue = fieldValue.Elem() - if !fieldValue.IsValid() || fieldPtr.IsNil() { - fieldValue = reflect.New(f).Elem() - } - } - isPtr = true - fallthrough - case reflect.Struct: - parentTable, err := ctx.engine.mapType(fieldValue) - if err != nil { - return err - } - for _, col := range parentTable.Columns() { - col.FieldName = fmt.Sprintf("%v.%v", ctx.col.FieldName, col.FieldName) - - var tagPrefix = ctx.col.FieldName - if len(ctx.params) > 0 { - col.Nullable = isPtr - tagPrefix = ctx.params[0] - if col.IsPrimaryKey { - col.Name = ctx.col.FieldName - col.IsPrimaryKey = false - } else { - col.Name = fmt.Sprintf("%v%v", tagPrefix, col.Name) - } - } - - if col.Nullable { - col.IsAutoIncrement = false - col.IsPrimaryKey = false - } - - ctx.table.AddColumn(col) - for indexName, indexType := range col.Indexes { - addIndex(indexName, ctx.table, col, indexType) - } - } - default: - //TODO: warning - } - return nil -} - -// CacheTagHandler describes cache tag handler -func CacheTagHandler(ctx *tagContext) error { - if !ctx.hasCacheTag { - ctx.hasCacheTag = true - } - return nil -} - -// NoCacheTagHandler describes nocache tag handler -func NoCacheTagHandler(ctx *tagContext) error { - if !ctx.hasNoCacheTag { - ctx.hasNoCacheTag = true - } - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/tag_id_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/tag_id_test.go deleted file mode 100644 index f1c5a6bc1..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/tag_id_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "testing" - - "xorm.io/core" - "github.com/stretchr/testify/assert" -) - -type IDGonicMapper struct { - ID int64 -} - -func TestGonicMapperID(t *testing.T) { - assert.NoError(t, prepareEngine()) - - oldMapper := testEngine.GetColumnMapper() - testEngine.UnMapType(rValue(new(IDGonicMapper)).Type()) - testEngine.SetMapper(core.LintGonicMapper) - defer func() { - testEngine.UnMapType(rValue(new(IDGonicMapper)).Type()) - testEngine.SetMapper(oldMapper) - }() - - err := testEngine.CreateTables(new(IDGonicMapper)) - if err != nil { - t.Fatal(err) - } - - tables, err := testEngine.DBMetas() - if err != nil { - t.Fatal(err) - } - - for _, tb := range tables { - if tb.Name == "id_gonic_mapper" { - if len(tb.PKColumns()) != 1 || tb.PKColumns()[0].Name != "id" { - t.Fatal(tb) - } - return - } - } - - t.Fatal("not table id_gonic_mapper") -} - -type IDSameMapper struct { - ID int64 -} - -func TestSameMapperID(t *testing.T) { - assert.NoError(t, prepareEngine()) - - oldMapper := testEngine.GetColumnMapper() - testEngine.UnMapType(rValue(new(IDSameMapper)).Type()) - testEngine.SetMapper(core.SameMapper{}) - defer func() { - testEngine.UnMapType(rValue(new(IDSameMapper)).Type()) - testEngine.SetMapper(oldMapper) - }() - - err := testEngine.CreateTables(new(IDSameMapper)) - if err != nil { - t.Fatal(err) - } - - tables, err := testEngine.DBMetas() - if err != nil { - t.Fatal(err) - } - - for _, tb := range tables { - if tb.Name == "IDSameMapper" { - if len(tb.PKColumns()) != 1 || tb.PKColumns()[0].Name != "ID" { - t.Fatal(tb) - } - return - } - } - t.Fatal("not table IDSameMapper") -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/tag_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/tag_test.go deleted file mode 100644 index 979ba9297..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/tag_test.go +++ /dev/null @@ -1,600 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" - "xorm.io/core" -) - -type UserCU struct { - Id int64 - Name string - Created time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` -} - -func TestCreatedAndUpdated(t *testing.T) { - assert.NoError(t, prepareEngine()) - - u := new(UserCU) - err := testEngine.DropTables(u) - assert.NoError(t, err) - - err = testEngine.CreateTables(u) - assert.NoError(t, err) - - u.Name = "sss" - cnt, err := testEngine.Insert(u) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - u.Name = "xxx" - cnt, err = testEngine.ID(u.Id).Update(u) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - u.Id = 0 - u.Created = time.Now().Add(-time.Hour * 24 * 365) - u.Updated = u.Created - cnt, err = testEngine.NoAutoTime().Insert(u) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) -} - -type StrangeName struct { - Id_t int64 `xorm:"pk autoincr"` - Name string -} - -func TestStrangeName(t *testing.T) { - assert.NoError(t, prepareEngine()) - - err := testEngine.DropTables(new(StrangeName)) - assert.NoError(t, err) - - err = testEngine.CreateTables(new(StrangeName)) - assert.NoError(t, err) - - _, err = testEngine.Insert(&StrangeName{Name: "sfsfdsfds"}) - assert.NoError(t, err) - - beans := make([]StrangeName, 0) - err = testEngine.Find(&beans) - assert.NoError(t, err) -} - -func TestCreatedUpdated(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type CreatedUpdated struct { - Id int64 - Name string - Value float64 `xorm:"numeric"` - Created time.Time `xorm:"created"` - Created2 time.Time `xorm:"created"` - Updated time.Time `xorm:"updated"` - } - - err := testEngine.Sync2(&CreatedUpdated{}) - assert.NoError(t, err) - - c := &CreatedUpdated{Name: "test"} - _, err = testEngine.Insert(c) - assert.NoError(t, err) - - c2 := new(CreatedUpdated) - has, err := testEngine.ID(c.Id).Get(c2) - assert.NoError(t, err) - - assert.True(t, has) - - c2.Value -= 1 - _, err = testEngine.ID(c2.Id).Update(c2) - assert.NoError(t, err) -} - -func TestCreatedUpdatedInt64(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type CreatedUpdatedInt64 struct { - Id int64 - Name string - Value float64 `xorm:"numeric"` - Created int64 `xorm:"created"` - Created2 int64 `xorm:"created"` - Updated int64 `xorm:"updated"` - } - - assertSync(t, &CreatedUpdatedInt64{}) - - c := &CreatedUpdatedInt64{Name: "test"} - _, err := testEngine.Insert(c) - assert.NoError(t, err) - - c2 := new(CreatedUpdatedInt64) - has, err := testEngine.ID(c.Id).Get(c2) - assert.NoError(t, err) - assert.True(t, has) - - c2.Value -= 1 - _, err = testEngine.ID(c2.Id).Update(c2) - assert.NoError(t, err) -} - -type Lowercase struct { - Id int64 - Name string - ended int64 `xorm:"-"` -} - -func TestLowerCase(t *testing.T) { - assert.NoError(t, prepareEngine()) - - err := testEngine.Sync2(&Lowercase{}) - assert.NoError(t, err) - _, err = testEngine.Where("id > 0").Delete(&Lowercase{}) - assert.NoError(t, err) - - _, err = testEngine.Insert(&Lowercase{ended: 1}) - assert.NoError(t, err) - - ls := make([]Lowercase, 0) - err = testEngine.Find(&ls) - assert.NoError(t, err) - assert.EqualValues(t, 1, len(ls)) -} - -func TestAutoIncrTag(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type TestAutoIncr1 struct { - Id int64 - } - - tb := testEngine.TableInfo(new(TestAutoIncr1)) - cols := tb.Columns() - assert.EqualValues(t, 1, len(cols)) - assert.True(t, cols[0].IsAutoIncrement) - assert.True(t, cols[0].IsPrimaryKey) - assert.Equal(t, "id", cols[0].Name) - - type TestAutoIncr2 struct { - Id int64 `xorm:"id"` - } - - tb = testEngine.TableInfo(new(TestAutoIncr2)) - cols = tb.Columns() - assert.EqualValues(t, 1, len(cols)) - assert.False(t, cols[0].IsAutoIncrement) - assert.False(t, cols[0].IsPrimaryKey) - assert.Equal(t, "id", cols[0].Name) - - type TestAutoIncr3 struct { - Id int64 `xorm:"'ID'"` - } - - tb = testEngine.TableInfo(new(TestAutoIncr3)) - cols = tb.Columns() - assert.EqualValues(t, 1, len(cols)) - assert.False(t, cols[0].IsAutoIncrement) - assert.False(t, cols[0].IsPrimaryKey) - assert.Equal(t, "ID", cols[0].Name) - - type TestAutoIncr4 struct { - Id int64 `xorm:"pk"` - } - - tb = testEngine.TableInfo(new(TestAutoIncr4)) - cols = tb.Columns() - assert.EqualValues(t, 1, len(cols)) - assert.False(t, cols[0].IsAutoIncrement) - assert.True(t, cols[0].IsPrimaryKey) - assert.Equal(t, "id", cols[0].Name) -} - -func TestTagComment(t *testing.T) { - assert.NoError(t, prepareEngine()) - // FIXME: only support mysql - if testEngine.Dialect().DriverName() != core.MYSQL { - return - } - - type TestComment1 struct { - Id int64 `xorm:"comment(主键)"` - } - - assert.NoError(t, testEngine.Sync2(new(TestComment1))) - - tables, err := testEngine.DBMetas() - assert.NoError(t, err) - assert.EqualValues(t, 1, len(tables)) - assert.EqualValues(t, 1, len(tables[0].Columns())) - assert.EqualValues(t, "主键", tables[0].Columns()[0].Comment) - - assert.NoError(t, testEngine.DropTables(new(TestComment1))) - - type TestComment2 struct { - Id int64 `xorm:"comment('主键')"` - } - - assert.NoError(t, testEngine.Sync2(new(TestComment2))) - - tables, err = testEngine.DBMetas() - assert.NoError(t, err) - assert.EqualValues(t, 1, len(tables)) - assert.EqualValues(t, 1, len(tables[0].Columns())) - assert.EqualValues(t, "主键", tables[0].Columns()[0].Comment) -} - -func TestTagDefault(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type DefaultStruct struct { - Id int64 - Name string - Age int `xorm:"default(10)"` - } - - assertSync(t, new(DefaultStruct)) - - tables, err := testEngine.DBMetas() - assert.NoError(t, err) - - var defaultVal string - var isDefaultExist bool - tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct") - for _, table := range tables { - if table.Name == tableName { - col := table.GetColumn("age") - assert.NotNil(t, col) - defaultVal = col.Default - isDefaultExist = !col.DefaultIsEmpty - break - } - } - assert.True(t, isDefaultExist) - assert.EqualValues(t, "10", defaultVal) - - cnt, err := testEngine.Omit("age").Insert(&DefaultStruct{ - Name: "test", - Age: 20, - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var s DefaultStruct - has, err := testEngine.ID(1).Get(&s) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, 10, s.Age) - assert.EqualValues(t, "test", s.Name) -} - -func TestTagDefault2(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type DefaultStruct2 struct { - Id int64 - Name string - } - - assertSync(t, new(DefaultStruct2)) - - tables, err := testEngine.DBMetas() - assert.NoError(t, err) - - var defaultVal string - var isDefaultExist bool - tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct2") - for _, table := range tables { - if table.Name == tableName { - col := table.GetColumn("name") - assert.NotNil(t, col) - defaultVal = col.Default - isDefaultExist = !col.DefaultIsEmpty - break - } - } - assert.False(t, isDefaultExist, fmt.Sprintf("default value is --%v--", defaultVal)) - assert.EqualValues(t, "", defaultVal) -} - -func TestTagDefault3(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type DefaultStruct3 struct { - Id int64 - Name string `xorm:"default('myname')"` - } - - assertSync(t, new(DefaultStruct3)) - - tables, err := testEngine.DBMetas() - assert.NoError(t, err) - - var defaultVal string - var isDefaultExist bool - tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct3") - for _, table := range tables { - if table.Name == tableName { - col := table.GetColumn("name") - assert.NotNil(t, col) - defaultVal = col.Default - isDefaultExist = !col.DefaultIsEmpty - break - } - } - assert.True(t, isDefaultExist) - assert.EqualValues(t, "'myname'", defaultVal) -} - -func TestTagDefault4(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type DefaultStruct4 struct { - Id int64 - Created time.Time `xorm:"default(CURRENT_TIMESTAMP)"` - } - - assertSync(t, new(DefaultStruct4)) - - tables, err := testEngine.DBMetas() - assert.NoError(t, err) - - var defaultVal string - var isDefaultExist bool - tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct4") - for _, table := range tables { - if table.Name == tableName { - col := table.GetColumn("created") - assert.NotNil(t, col) - defaultVal = col.Default - isDefaultExist = !col.DefaultIsEmpty - break - } - } - assert.True(t, isDefaultExist) - assert.True(t, "CURRENT_TIMESTAMP" == defaultVal || - "now()" == defaultVal || - "getdate" == defaultVal, defaultVal) -} - -func TestTagDefault5(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type DefaultStruct5 struct { - Id int64 - Created time.Time `xorm:"default('2006-01-02 15:04:05')"` - } - - assertSync(t, new(DefaultStruct5)) - table := testEngine.TableInfo(new(DefaultStruct5)) - createdCol := table.GetColumn("created") - assert.NotNil(t, createdCol) - assert.EqualValues(t, "'2006-01-02 15:04:05'", createdCol.Default) - assert.False(t, createdCol.DefaultIsEmpty) - - tables, err := testEngine.DBMetas() - assert.NoError(t, err) - - var defaultVal string - var isDefaultExist bool - tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct5") - for _, table := range tables { - if table.Name == tableName { - col := table.GetColumn("created") - assert.NotNil(t, col) - defaultVal = col.Default - isDefaultExist = !col.DefaultIsEmpty - break - } - } - assert.True(t, isDefaultExist) - assert.EqualValues(t, "'2006-01-02 15:04:05'", defaultVal) -} - -func TestTagDefault6(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type DefaultStruct6 struct { - Id int64 - IsMan bool `xorm:"default(true)"` - } - - assertSync(t, new(DefaultStruct6)) - - tables, err := testEngine.DBMetas() - assert.NoError(t, err) - - var defaultVal string - var isDefaultExist bool - tableName := testEngine.GetColumnMapper().Obj2Table("DefaultStruct6") - for _, table := range tables { - if table.Name == tableName { - col := table.GetColumn("is_man") - assert.NotNil(t, col) - defaultVal = col.Default - isDefaultExist = !col.DefaultIsEmpty - break - } - } - assert.True(t, isDefaultExist) - if defaultVal == "1" { - defaultVal = "true" - } else if defaultVal == "0" { - defaultVal = "false" - } - assert.EqualValues(t, "true", defaultVal) -} - -func TestTagsDirection(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type OnlyFromDBStruct struct { - Id int64 - Name string - Uuid string `xorm:"<- default '1'"` - } - - assertSync(t, new(OnlyFromDBStruct)) - - cnt, err := testEngine.Insert(&OnlyFromDBStruct{ - Name: "test", - Uuid: "2", - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var s OnlyFromDBStruct - has, err := testEngine.ID(1).Get(&s) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, "1", s.Uuid) - assert.EqualValues(t, "test", s.Name) - - cnt, err = testEngine.ID(1).Update(&OnlyFromDBStruct{ - Uuid: "3", - Name: "test1", - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var s3 OnlyFromDBStruct - has, err = testEngine.ID(1).Get(&s3) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, "1", s3.Uuid) - assert.EqualValues(t, "test1", s3.Name) - - type OnlyToDBStruct struct { - Id int64 - Name string - Uuid string `xorm:"->"` - } - - assertSync(t, new(OnlyToDBStruct)) - - cnt, err = testEngine.Insert(&OnlyToDBStruct{ - Name: "test", - Uuid: "2", - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var s2 OnlyToDBStruct - has, err = testEngine.ID(1).Get(&s2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, "", s2.Uuid) - assert.EqualValues(t, "test", s2.Name) -} - -func TestTagTime(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type TagUTCStruct struct { - Id int64 - Name string - Created time.Time `xorm:"created utc"` - } - - assertSync(t, new(TagUTCStruct)) - - assert.EqualValues(t, time.Local.String(), testEngine.GetTZLocation().String()) - - s := TagUTCStruct{ - Name: "utc", - } - cnt, err := testEngine.Insert(&s) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var u TagUTCStruct - has, err := testEngine.ID(1).Get(&u) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, s.Created.Format("2006-01-02 15:04:05"), u.Created.Format("2006-01-02 15:04:05")) - - var tm string - has, err = testEngine.Table("tag_u_t_c_struct").Cols("created").Get(&tm) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, s.Created.UTC().Format("2006-01-02 15:04:05"), - strings.Replace(strings.Replace(tm, "T", " ", -1), "Z", "", -1)) -} - -func TestSplitTag(t *testing.T) { - var cases = []struct { - tag string - tags []string - }{ - {"not null default '2000-01-01 00:00:00' TIMESTAMP", []string{"not", "null", "default", "'2000-01-01 00:00:00'", "TIMESTAMP"}}, - {"TEXT", []string{"TEXT"}}, - {"default('2000-01-01 00:00:00')", []string{"default('2000-01-01 00:00:00')"}}, - {"json binary", []string{"json", "binary"}}, - } - - for _, kase := range cases { - tags := splitTag(kase.tag) - if !sliceEq(tags, kase.tags) { - t.Fatalf("[%d]%v is not equal [%d]%v", len(tags), tags, len(kase.tags), kase.tags) - } - } -} - -func TestTagAutoIncr(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type TagAutoIncr struct { - Id int64 - Name string - } - - assertSync(t, new(TagAutoIncr)) - - tables, err := testEngine.DBMetas() - assert.NoError(t, err) - assert.EqualValues(t, 1, len(tables)) - assert.EqualValues(t, tableMapper.Obj2Table("TagAutoIncr"), tables[0].Name) - col := tables[0].GetColumn(colMapper.Obj2Table("Id")) - assert.NotNil(t, col) - assert.True(t, col.IsPrimaryKey) - assert.True(t, col.IsAutoIncrement) - - col2 := tables[0].GetColumn(colMapper.Obj2Table("Name")) - assert.NotNil(t, col2) - assert.False(t, col2.IsPrimaryKey) - assert.False(t, col2.IsAutoIncrement) -} - -func TestTagPrimarykey(t *testing.T) { - assert.NoError(t, prepareEngine()) - type TagPrimaryKey struct { - Id int64 `xorm:"pk"` - Name string `xorm:"VARCHAR(20) pk"` - } - - assertSync(t, new(TagPrimaryKey)) - - tables, err := testEngine.DBMetas() - assert.NoError(t, err) - assert.EqualValues(t, 1, len(tables)) - assert.EqualValues(t, tableMapper.Obj2Table("TagPrimaryKey"), tables[0].Name) - col := tables[0].GetColumn(colMapper.Obj2Table("Id")) - assert.NotNil(t, col) - assert.True(t, col.IsPrimaryKey) - assert.False(t, col.IsAutoIncrement) - - col2 := tables[0].GetColumn(colMapper.Obj2Table("Name")) - assert.NotNil(t, col2) - assert.True(t, col2.IsPrimaryKey) - assert.False(t, col2.IsAutoIncrement) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mssql.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mssql.sh deleted file mode 100644 index 7f060cff3..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mssql.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=mssql -conn_str="server=localhost;user id=sa;password=yourStrong(!)Password;database=xorm_test" \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mssql_cache.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mssql_cache.sh deleted file mode 100644 index 76efd6ca0..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mssql_cache.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=mssql -conn_str="server=192.168.1.58;user id=sa;password=123456;database=xorm_test" -cache=true \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mymysql.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mymysql.sh deleted file mode 100644 index f7780d14f..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mymysql.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=mymysql -conn_str="xorm_test/root/" \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mymysql_cache.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mymysql_cache.sh deleted file mode 100644 index 0100286d6..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mymysql_cache.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=mymysql -conn_str="xorm_test/root/" -cache=true \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mysql.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mysql.sh deleted file mode 100644 index 650e4ee17..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mysql.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=mysql -conn_str="root:@/xorm_test" \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mysql_cache.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mysql_cache.sh deleted file mode 100644 index c542e7359..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_mysql_cache.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=mysql -conn_str="root:@/xorm_test" -cache=true \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_postgres.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_postgres.sh deleted file mode 100644 index dc1152e0a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_postgres.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=postgres -conn_str="dbname=xorm_test sslmode=disable" \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_postgres_cache.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_postgres_cache.sh deleted file mode 100644 index 462fc948c..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_postgres_cache.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=postgres -conn_str="dbname=xorm_test sslmode=disable" -cache=true \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_sqlite.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_sqlite.sh deleted file mode 100644 index 6352b5cb5..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_sqlite.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_sqlite_cache.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_sqlite_cache.sh deleted file mode 100644 index 75a054c3f..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_sqlite_cache.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=sqlite3 -conn_str="./test.db?cache=shared&mode=rwc" -cache=true \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_tidb.sh b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_tidb.sh deleted file mode 100644 index 03d2d6cd8..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/test_tidb.sh +++ /dev/null @@ -1 +0,0 @@ -go test -db=mysql -conn_str="root:@tcp(localhost:4000)/xorm_test" -ignore_select_update=true \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/time_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/time_test.go deleted file mode 100644 index b7e4d12b2..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/time_test.go +++ /dev/null @@ -1,476 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "strings" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestTimeUserTime(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type TimeUser struct { - Id string - OperTime time.Time - } - - assertSync(t, new(TimeUser)) - - var user = TimeUser{ - Id: "lunny", - OperTime: time.Now(), - } - - fmt.Println("user", user.OperTime) - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var user2 TimeUser - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.OperTime.Unix(), user2.OperTime.Unix()) - assert.EqualValues(t, formatTime(user.OperTime), formatTime(user2.OperTime)) - fmt.Println("user2", user2.OperTime) -} - -func TestTimeUserTimeDiffLoc(t *testing.T) { - assert.NoError(t, prepareEngine()) - loc, err := time.LoadLocation("Asia/Shanghai") - assert.NoError(t, err) - testEngine.SetTZLocation(loc) - dbLoc, err := time.LoadLocation("America/New_York") - assert.NoError(t, err) - testEngine.SetTZDatabase(dbLoc) - - type TimeUser2 struct { - Id string - OperTime time.Time - } - - assertSync(t, new(TimeUser2)) - - var user = TimeUser2{ - Id: "lunny", - OperTime: time.Now(), - } - - fmt.Println("user", user.OperTime) - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var user2 TimeUser2 - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.OperTime.Unix(), user2.OperTime.Unix()) - assert.EqualValues(t, formatTime(user.OperTime.In(loc)), formatTime(user2.OperTime)) - fmt.Println("user2", user2.OperTime) -} - -func TestTimeUserCreated(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type UserCreated struct { - Id string - CreatedAt time.Time `xorm:"created"` - } - - assertSync(t, new(UserCreated)) - - var user = UserCreated{ - Id: "lunny", - } - - fmt.Println("user", user.CreatedAt) - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var user2 UserCreated - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) - fmt.Println("user2", user2.CreatedAt) -} - -func TestTimeUserCreatedDiffLoc(t *testing.T) { - assert.NoError(t, prepareEngine()) - loc, err := time.LoadLocation("Asia/Shanghai") - assert.NoError(t, err) - testEngine.SetTZLocation(loc) - dbLoc, err := time.LoadLocation("America/New_York") - assert.NoError(t, err) - testEngine.SetTZDatabase(dbLoc) - - type UserCreated2 struct { - Id string - CreatedAt time.Time `xorm:"created"` - } - - assertSync(t, new(UserCreated2)) - - var user = UserCreated2{ - Id: "lunny", - } - - fmt.Println("user", user.CreatedAt) - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var user2 UserCreated2 - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) - fmt.Println("user2", user2.CreatedAt) -} - -func TestTimeUserUpdated(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type UserUpdated struct { - Id string - CreatedAt time.Time `xorm:"created"` - UpdatedAt time.Time `xorm:"updated"` - } - - assertSync(t, new(UserUpdated)) - - var user = UserUpdated{ - Id: "lunny", - } - - fmt.Println("user", user.CreatedAt, user.UpdatedAt) - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var user2 UserUpdated - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) - assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) - assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt)) - fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt) - - var user3 = UserUpdated{ - Id: "lunny2", - } - - cnt, err = testEngine.Update(&user3) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - assert.True(t, user.UpdatedAt.Unix() <= user3.UpdatedAt.Unix()) - - var user4 UserUpdated - has, err = testEngine.Get(&user4) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user4.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user4.CreatedAt)) - assert.EqualValues(t, user3.UpdatedAt.Unix(), user4.UpdatedAt.Unix()) - assert.EqualValues(t, formatTime(user3.UpdatedAt), formatTime(user4.UpdatedAt)) - fmt.Println("user3", user.CreatedAt, user4.UpdatedAt) -} - -func TestTimeUserUpdatedDiffLoc(t *testing.T) { - assert.NoError(t, prepareEngine()) - loc, err := time.LoadLocation("Asia/Shanghai") - assert.NoError(t, err) - testEngine.SetTZLocation(loc) - dbLoc, err := time.LoadLocation("America/New_York") - assert.NoError(t, err) - testEngine.SetTZDatabase(dbLoc) - - type UserUpdated2 struct { - Id string - CreatedAt time.Time `xorm:"created"` - UpdatedAt time.Time `xorm:"updated"` - } - - assertSync(t, new(UserUpdated2)) - - var user = UserUpdated2{ - Id: "lunny", - } - - fmt.Println("user", user.CreatedAt, user.UpdatedAt) - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var user2 UserUpdated2 - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) - assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) - assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt)) - fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt) - - var user3 = UserUpdated2{ - Id: "lunny2", - } - - cnt, err = testEngine.Update(&user3) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - assert.True(t, user.UpdatedAt.Unix() <= user3.UpdatedAt.Unix()) - - var user4 UserUpdated2 - has, err = testEngine.Get(&user4) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user4.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user4.CreatedAt)) - assert.EqualValues(t, user3.UpdatedAt.Unix(), user4.UpdatedAt.Unix()) - assert.EqualValues(t, formatTime(user3.UpdatedAt), formatTime(user4.UpdatedAt)) - fmt.Println("user3", user.CreatedAt, user4.UpdatedAt) -} - -func TestTimeUserDeleted(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type UserDeleted struct { - Id string - CreatedAt time.Time `xorm:"created"` - UpdatedAt time.Time `xorm:"updated"` - DeletedAt time.Time `xorm:"deleted"` - } - - assertSync(t, new(UserDeleted)) - - var user = UserDeleted{ - Id: "lunny", - } - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt) - - var user2 UserDeleted - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) - assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) - assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt)) - assert.True(t, isTimeZero(user2.DeletedAt)) - fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt) - - var user3 UserDeleted - cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - assert.True(t, !isTimeZero(user3.DeletedAt)) - - var user4 UserDeleted - has, err = testEngine.Unscoped().Get(&user4) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix()) - assert.EqualValues(t, formatTime(user3.DeletedAt), formatTime(user4.DeletedAt)) - fmt.Println("user3", user3.DeletedAt, user4.DeletedAt) -} - -func TestTimeUserDeletedDiffLoc(t *testing.T) { - assert.NoError(t, prepareEngine()) - loc, err := time.LoadLocation("Asia/Shanghai") - assert.NoError(t, err) - testEngine.SetTZLocation(loc) - dbLoc, err := time.LoadLocation("America/New_York") - assert.NoError(t, err) - testEngine.SetTZDatabase(dbLoc) - - type UserDeleted2 struct { - Id string - CreatedAt time.Time `xorm:"created"` - UpdatedAt time.Time `xorm:"updated"` - DeletedAt time.Time `xorm:"deleted"` - } - - assertSync(t, new(UserDeleted2)) - - var user = UserDeleted2{ - Id: "lunny", - } - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt) - - var user2 UserDeleted2 - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(user.CreatedAt), formatTime(user2.CreatedAt)) - assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) - assert.EqualValues(t, formatTime(user.UpdatedAt), formatTime(user2.UpdatedAt)) - assert.True(t, isTimeZero(user2.DeletedAt)) - fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt) - - var user3 UserDeleted2 - cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - assert.True(t, !isTimeZero(user3.DeletedAt)) - - var user4 UserDeleted2 - has, err = testEngine.Unscoped().Get(&user4) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix()) - assert.EqualValues(t, formatTime(user3.DeletedAt), formatTime(user4.DeletedAt)) - fmt.Println("user3", user3.DeletedAt, user4.DeletedAt) -} - -type JsonDate time.Time - -func (j JsonDate) MarshalJSON() ([]byte, error) { - if time.Time(j).IsZero() { - return []byte(`""`), nil - } - return []byte(`"` + time.Time(j).Format("2006-01-02 15:04:05") + `"`), nil -} - -func (j *JsonDate) UnmarshalJSON(value []byte) error { - var v = strings.TrimSpace(strings.Trim(string(value), "\"")) - - t, err := time.ParseInLocation("2006-01-02 15:04:05", v, time.Local) - if err != nil { - return err - } - *j = JsonDate(t) - return nil -} - -func (j *JsonDate) Unix() int64 { - return (*time.Time)(j).Unix() -} - -func TestCustomTimeUserDeleted(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type UserDeleted3 struct { - Id string - CreatedAt JsonDate `xorm:"created"` - UpdatedAt JsonDate `xorm:"updated"` - DeletedAt JsonDate `xorm:"deleted"` - } - - assertSync(t, new(UserDeleted3)) - - var user = UserDeleted3{ - Id: "lunny", - } - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt) - - var user2 UserDeleted3 - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(time.Time(user.CreatedAt)), formatTime(time.Time(user2.CreatedAt))) - assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) - assert.EqualValues(t, formatTime(time.Time(user.UpdatedAt)), formatTime(time.Time(user2.UpdatedAt))) - assert.True(t, isTimeZero(time.Time(user2.DeletedAt))) - fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt) - - var user3 UserDeleted3 - cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - assert.True(t, !isTimeZero(time.Time(user3.DeletedAt))) - - var user4 UserDeleted3 - has, err = testEngine.Unscoped().Get(&user4) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix()) - assert.EqualValues(t, formatTime(time.Time(user3.DeletedAt)), formatTime(time.Time(user4.DeletedAt))) - fmt.Println("user3", user3.DeletedAt, user4.DeletedAt) -} - -func TestCustomTimeUserDeletedDiffLoc(t *testing.T) { - assert.NoError(t, prepareEngine()) - loc, err := time.LoadLocation("Asia/Shanghai") - assert.NoError(t, err) - testEngine.SetTZLocation(loc) - dbLoc, err := time.LoadLocation("America/New_York") - assert.NoError(t, err) - testEngine.SetTZDatabase(dbLoc) - - type UserDeleted4 struct { - Id string - CreatedAt JsonDate `xorm:"created"` - UpdatedAt JsonDate `xorm:"updated"` - DeletedAt JsonDate `xorm:"deleted"` - } - - assertSync(t, new(UserDeleted4)) - - var user = UserDeleted4{ - Id: "lunny", - } - - cnt, err := testEngine.Insert(&user) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - fmt.Println("user", user.CreatedAt, user.UpdatedAt, user.DeletedAt) - - var user2 UserDeleted4 - has, err := testEngine.Get(&user2) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user.CreatedAt.Unix(), user2.CreatedAt.Unix()) - assert.EqualValues(t, formatTime(time.Time(user.CreatedAt)), formatTime(time.Time(user2.CreatedAt))) - assert.EqualValues(t, user.UpdatedAt.Unix(), user2.UpdatedAt.Unix()) - assert.EqualValues(t, formatTime(time.Time(user.UpdatedAt)), formatTime(time.Time(user2.UpdatedAt))) - assert.True(t, isTimeZero(time.Time(user2.DeletedAt))) - fmt.Println("user2", user2.CreatedAt, user2.UpdatedAt, user2.DeletedAt) - - var user3 UserDeleted4 - cnt, err = testEngine.Where("id = ?", "lunny").Delete(&user3) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - assert.True(t, !isTimeZero(time.Time(user3.DeletedAt))) - - var user4 UserDeleted4 - has, err = testEngine.Unscoped().Get(&user4) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, user3.DeletedAt.Unix(), user4.DeletedAt.Unix()) - assert.EqualValues(t, formatTime(time.Time(user3.DeletedAt)), formatTime(time.Time(user4.DeletedAt))) - fmt.Println("user3", user3.DeletedAt, user4.DeletedAt) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/transaction.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/transaction.go deleted file mode 100644 index 4104103fd..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/transaction.go +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright 2018 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -// Transaction Execute sql wrapped in a transaction(abbr as tx), tx will automatic commit if no errors occurred -func (engine *Engine) Transaction(f func(*Session) (interface{}, error)) (interface{}, error) { - session := engine.NewSession() - defer session.Close() - - if err := session.Begin(); err != nil { - return nil, err - } - - result, err := f(session) - if err != nil { - return nil, err - } - - if err := session.Commit(); err != nil { - return nil, err - } - - return result, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/transancation_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/transancation_test.go deleted file mode 100644 index b9a898787..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/transancation_test.go +++ /dev/null @@ -1,52 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "fmt" - "testing" - "time" - - "github.com/stretchr/testify/assert" -) - -func TestAutoTransaction(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type TestTx struct { - Id int64 `xorm:"autoincr pk"` - Msg string `xorm:"varchar(255)"` - Created time.Time `xorm:"created"` - } - - assert.NoError(t, testEngine.Sync2(new(TestTx))) - - engine := testEngine.(*Engine) - - // will success - engine.Transaction(func(session *Session) (interface{}, error) { - _, err := session.Insert(TestTx{Msg: "hi"}) - assert.NoError(t, err) - - return nil, nil - }) - - has, err := engine.Exist(&TestTx{Msg: "hi"}) - assert.NoError(t, err) - assert.EqualValues(t, true, has) - - // will rollback - _, err = engine.Transaction(func(session *Session) (interface{}, error) { - _, err := session.Insert(TestTx{Msg: "hello"}) - assert.NoError(t, err) - - return nil, fmt.Errorf("rollback") - }) - assert.Error(t, err) - - has, err = engine.Exist(&TestTx{Msg: "hello"}) - assert.NoError(t, err) - assert.EqualValues(t, false, has) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/types.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/types.go deleted file mode 100644 index c76a54606..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/types.go +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "reflect" - - "xorm.io/core" -) - -var ( - ptrPkType = reflect.TypeOf(&core.PK{}) - pkType = reflect.TypeOf(core.PK{}) -) diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/types_null_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/types_null_test.go deleted file mode 100644 index 22fc1024f..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/types_null_test.go +++ /dev/null @@ -1,404 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "database/sql/driver" - "errors" - "fmt" - "strconv" - "strings" - "testing" - - "github.com/stretchr/testify/assert" -) - -type NullType struct { - Id int `xorm:"pk autoincr"` - Name sql.NullString - Age sql.NullInt64 - Height sql.NullFloat64 - IsMan sql.NullBool `xorm:"null"` - CustomStruct CustomStruct `xorm:"valchar(64) null"` -} - -type CustomStruct struct { - Year int - Month int - Day int -} - -func (CustomStruct) String() string { - return "CustomStruct" -} - -func (m *CustomStruct) Scan(value interface{}) error { - if value == nil { - m.Year, m.Month, m.Day = 0, 0, 0 - return nil - } - - if s, ok := value.([]byte); ok { - seps := strings.Split(string(s), "/") - m.Year, _ = strconv.Atoi(seps[0]) - m.Month, _ = strconv.Atoi(seps[1]) - m.Day, _ = strconv.Atoi(seps[2]) - return nil - } - - return errors.New("scan data not fit []byte") -} - -func (m CustomStruct) Value() (driver.Value, error) { - return fmt.Sprintf("%d/%d/%d", m.Year, m.Month, m.Day), nil -} - -func TestCreateNullStructTable(t *testing.T) { - assert.NoError(t, prepareEngine()) - - err := testEngine.CreateTables(new(NullType)) - if err != nil { - t.Error(err) - panic(err) - } -} - -func TestDropNullStructTable(t *testing.T) { - assert.NoError(t, prepareEngine()) - - err := testEngine.DropTables(new(NullType)) - if err != nil { - t.Error(err) - panic(err) - } -} - -func TestNullStructInsert(t *testing.T) { - assert.NoError(t, prepareEngine()) - assertSync(t, new(NullType)) - - if true { - item := new(NullType) - _, err := testEngine.Insert(item) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(item) - if item.Id != 1 { - err = errors.New("insert error") - t.Error(err) - panic(err) - } - } - - if true { - item := NullType{ - Name: sql.NullString{"haolei", true}, - Age: sql.NullInt64{34, true}, - Height: sql.NullFloat64{1.72, true}, - IsMan: sql.NullBool{true, true}, - } - _, err := testEngine.Insert(&item) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(item) - if item.Id != 2 { - err = errors.New("insert error") - t.Error(err) - panic(err) - } - } - - if true { - items := []NullType{} - - for i := 0; i < 5; i++ { - item := NullType{ - Name: sql.NullString{"haolei_" + fmt.Sprint(i+1), true}, - Age: sql.NullInt64{30 + int64(i), true}, - Height: sql.NullFloat64{1.5 + 1.1*float64(i), true}, - IsMan: sql.NullBool{true, true}, - CustomStruct: CustomStruct{i, i + 1, i + 2}, - } - - items = append(items, item) - } - - _, err := testEngine.Insert(&items) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(items) - } -} - -func TestNullStructUpdate(t *testing.T) { - assert.NoError(t, prepareEngine()) - assertSync(t, new(NullType)) - - _, err := testEngine.Insert([]NullType{ - { - Name: sql.NullString{ - String: "name1", - Valid: true, - }, - }, - { - Name: sql.NullString{ - String: "name2", - Valid: true, - }, - }, - { - Name: sql.NullString{ - String: "name3", - Valid: true, - }, - }, - { - Name: sql.NullString{ - String: "name4", - Valid: true, - }, - }, - }) - assert.NoError(t, err) - - if true { // 测试可插入NULL - item := new(NullType) - item.Age = sql.NullInt64{23, true} - item.Height = sql.NullFloat64{0, false} // update to NULL - - affected, err := testEngine.ID(2).Cols("age", "height", "is_man").Update(item) - if err != nil { - t.Error(err) - panic(err) - } - if affected != 1 { - err := errors.New("update failed") - t.Error(err) - panic(err) - } - } - - if true { // 测试In update - item := new(NullType) - item.Age = sql.NullInt64{23, true} - affected, err := testEngine.In("id", 3, 4).Cols("age", "height", "is_man").Update(item) - if err != nil { - t.Error(err) - panic(err) - } - if affected != 2 { - err := errors.New("update failed") - t.Error(err) - panic(err) - } - } - - if true { // 测试where - item := new(NullType) - item.Name = sql.NullString{"nullname", true} - item.IsMan = sql.NullBool{true, true} - item.Age = sql.NullInt64{34, true} - - _, err := testEngine.Where("age > ?", 34).Update(item) - if err != nil { - t.Error(err) - panic(err) - } - } - - if true { // 修改全部时,插入空值 - item := &NullType{ - Name: sql.NullString{"winxxp", true}, - Age: sql.NullInt64{30, true}, - Height: sql.NullFloat64{1.72, true}, - // IsMan: sql.NullBool{true, true}, - } - - _, err := testEngine.AllCols().ID(6).Update(item) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(item) - } - -} - -func TestNullStructFind(t *testing.T) { - assert.NoError(t, prepareEngine()) - assertSync(t, new(NullType)) - - _, err := testEngine.Insert([]NullType{ - { - Name: sql.NullString{ - String: "name1", - Valid: false, - }, - }, - { - Name: sql.NullString{ - String: "name2", - Valid: true, - }, - }, - { - Name: sql.NullString{ - String: "name3", - Valid: true, - }, - }, - { - Name: sql.NullString{ - String: "name4", - Valid: true, - }, - }, - }) - assert.NoError(t, err) - - if true { - item := new(NullType) - has, err := testEngine.ID(1).Get(item) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - t.Error(errors.New("no find id 1")) - panic(err) - } - fmt.Println(item) - if item.Id != 1 || item.Name.Valid || item.Age.Valid || item.Height.Valid || - item.IsMan.Valid { - err = errors.New("insert error") - t.Error(err) - panic(err) - } - } - - if true { - item := new(NullType) - item.Id = 2 - - has, err := testEngine.Get(item) - if err != nil { - t.Error(err) - panic(err) - } - if !has { - t.Error(errors.New("no find id 2")) - panic(err) - } - fmt.Println(item) - } - - if true { - item := make([]NullType, 0) - - err := testEngine.ID(2).Find(&item) - if err != nil { - t.Error(err) - panic(err) - } - - fmt.Println(item) - } - - if true { - item := make([]NullType, 0) - - err := testEngine.Asc("age").Find(&item) - if err != nil { - t.Error(err) - panic(err) - } - - for k, v := range item { - fmt.Println(k, v) - } - } -} - -func TestNullStructIterate(t *testing.T) { - assert.NoError(t, prepareEngine()) - assertSync(t, new(NullType)) - - if true { - err := testEngine.Where("age IS NOT NULL").OrderBy("age").Iterate(new(NullType), - func(i int, bean interface{}) error { - nultype := bean.(*NullType) - fmt.Println(i, nultype) - return nil - }) - if err != nil { - t.Error(err) - panic(err) - } - } -} - -func TestNullStructCount(t *testing.T) { - assert.NoError(t, prepareEngine()) - assertSync(t, new(NullType)) - - if true { - item := new(NullType) - total, err := testEngine.Where("age IS NOT NULL").Count(item) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(total) - } -} - -func TestNullStructRows(t *testing.T) { - assert.NoError(t, prepareEngine()) - assertSync(t, new(NullType)) - - item := new(NullType) - rows, err := testEngine.Where("id > ?", 1).Rows(item) - if err != nil { - t.Error(err) - panic(err) - } - defer rows.Close() - - for rows.Next() { - err = rows.Scan(item) - if err != nil { - t.Error(err) - panic(err) - } - fmt.Println(item) - } -} - -func TestNullStructDelete(t *testing.T) { - assert.NoError(t, prepareEngine()) - assertSync(t, new(NullType)) - - item := new(NullType) - - _, err := testEngine.ID(1).Delete(item) - if err != nil { - t.Error(err) - panic(err) - } - - _, err = testEngine.Where("id > ?", 1).Delete(item) - if err != nil { - t.Error(err) - panic(err) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/types_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/types_test.go deleted file mode 100644 index 274609b20..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/types_test.go +++ /dev/null @@ -1,343 +0,0 @@ -// Copyright 2017 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "errors" - "fmt" - "testing" - - "xorm.io/core" - "github.com/stretchr/testify/assert" -) - -func TestArrayField(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type ArrayStruct struct { - Id int64 - Name [20]byte `xorm:"char(80)"` - } - - assert.NoError(t, testEngine.Sync2(new(ArrayStruct))) - - var as = ArrayStruct{ - Name: [20]byte{ - 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, - }, - } - cnt, err := testEngine.Insert(&as) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var arr ArrayStruct - has, err := testEngine.ID(1).Get(&arr) - assert.NoError(t, err) - assert.Equal(t, true, has) - assert.Equal(t, as.Name, arr.Name) - - var arrs []ArrayStruct - err = testEngine.Find(&arrs) - assert.NoError(t, err) - assert.EqualValues(t, 1, len(arrs)) - assert.Equal(t, as.Name, arrs[0].Name) - - var newName = [20]byte{ - 90, 96, 96, 96, 96, - 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, - 96, 96, 96, 96, 96, - } - - cnt, err = testEngine.ID(1).Update(&ArrayStruct{ - Name: newName, - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var newArr ArrayStruct - has, err = testEngine.ID(1).Get(&newArr) - assert.NoError(t, err) - assert.Equal(t, true, has) - assert.Equal(t, newName, newArr.Name) - - cnt, err = testEngine.ID(1).Delete(new(ArrayStruct)) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var cfgArr ArrayStruct - has, err = testEngine.ID(1).Get(&cfgArr) - assert.NoError(t, err) - assert.Equal(t, false, has) -} - -func TestGetBytes(t *testing.T) { - assert.NoError(t, prepareEngine()) - - type Varbinary struct { - Data []byte `xorm:"VARBINARY(250)"` - } - - err := testEngine.Sync2(new(Varbinary)) - assert.NoError(t, err) - - cnt, err := testEngine.Insert(&Varbinary{ - Data: []byte("test"), - }) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - var b Varbinary - has, err := testEngine.Get(&b) - assert.NoError(t, err) - assert.Equal(t, true, has) - assert.Equal(t, "test", string(b.Data)) -} - -type ConvString string - -func (s *ConvString) FromDB(data []byte) error { - *s = ConvString("prefix---" + string(data)) - return nil -} - -func (s *ConvString) ToDB() ([]byte, error) { - return []byte(string(*s)), nil -} - -type ConvConfig struct { - Name string - Id int64 -} - -func (s *ConvConfig) FromDB(data []byte) error { - return DefaultJSONHandler.Unmarshal(data, s) -} - -func (s *ConvConfig) ToDB() ([]byte, error) { - return DefaultJSONHandler.Marshal(s) -} - -type SliceType []*ConvConfig - -func (s *SliceType) FromDB(data []byte) error { - return DefaultJSONHandler.Unmarshal(data, s) -} - -func (s *SliceType) ToDB() ([]byte, error) { - return DefaultJSONHandler.Marshal(s) -} - -type ConvStruct struct { - Conv ConvString - Conv2 *ConvString - Cfg1 ConvConfig - Cfg2 *ConvConfig `xorm:"TEXT"` - Cfg3 core.Conversion `xorm:"BLOB"` - Slice SliceType -} - -func (c *ConvStruct) BeforeSet(name string, cell Cell) { - if name == "cfg3" || name == "Cfg3" { - c.Cfg3 = new(ConvConfig) - } -} - -func TestConversion(t *testing.T) { - assert.NoError(t, prepareEngine()) - - c := new(ConvStruct) - assert.NoError(t, testEngine.DropTables(c)) - assert.NoError(t, testEngine.Sync2(c)) - - var s ConvString = "sssss" - c.Conv = "tttt" - c.Conv2 = &s - c.Cfg1 = ConvConfig{"mm", 1} - c.Cfg2 = &ConvConfig{"xx", 2} - c.Cfg3 = &ConvConfig{"zz", 3} - c.Slice = []*ConvConfig{{"yy", 4}, {"ff", 5}} - - _, err := testEngine.Insert(c) - assert.NoError(t, err) - - c1 := new(ConvStruct) - has, err := testEngine.Get(c1) - assert.NoError(t, err) - assert.True(t, has) - assert.EqualValues(t, "prefix---tttt", string(c1.Conv)) - assert.NotNil(t, c1.Conv2) - assert.EqualValues(t, "prefix---"+s, *c1.Conv2) - assert.EqualValues(t, c.Cfg1, c1.Cfg1) - assert.NotNil(t, c1.Cfg2) - assert.EqualValues(t, *c.Cfg2, *c1.Cfg2) - assert.NotNil(t, c1.Cfg3) - assert.EqualValues(t, *c.Cfg3.(*ConvConfig), *c1.Cfg3.(*ConvConfig)) - assert.EqualValues(t, 2, len(c1.Slice)) - assert.EqualValues(t, *c.Slice[0], *c1.Slice[0]) - assert.EqualValues(t, *c.Slice[1], *c1.Slice[1]) -} - -type MyInt int -type MyUInt uint -type MyFloat float64 - -type MyStruct struct { - Type MyInt - U MyUInt - F MyFloat - S MyString - IA []MyInt - UA []MyUInt - FA []MyFloat - SA []MyString - NameArray []string - Name string - UIA []uint - UIA8 []uint8 - UIA16 []uint16 - UIA32 []uint32 - UIA64 []uint64 - UI uint - //C64 complex64 - MSS map[string]string -} - -func TestCustomType1(t *testing.T) { - assert.NoError(t, prepareEngine()) - - err := testEngine.DropTables(&MyStruct{}) - assert.NoError(t, err) - - err = testEngine.CreateTables(&MyStruct{}) - assert.NoError(t, err) - - i := MyStruct{Name: "Test", Type: MyInt(1)} - i.U = 23 - i.F = 1.34 - i.S = "fafdsafdsaf" - i.UI = 2 - i.IA = []MyInt{1, 3, 5} - i.UIA = []uint{1, 3} - i.UIA16 = []uint16{2} - i.UIA32 = []uint32{4, 5} - i.UIA64 = []uint64{6, 7, 9} - i.UIA8 = []uint8{1, 2, 3, 4} - i.NameArray = []string{"ssss", "fsdf", "lllll, ss"} - i.MSS = map[string]string{"s": "sfds,ss", "x": "lfjljsl"} - - cnt, err := testEngine.Insert(&i) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - fmt.Println(i) - i.NameArray = []string{} - i.MSS = map[string]string{} - i.F = 0 - has, err := testEngine.Get(&i) - assert.NoError(t, err) - assert.True(t, has) - - ss := []MyStruct{} - err = testEngine.Find(&ss) - assert.NoError(t, err) - assert.EqualValues(t, 1, len(ss)) - assert.EqualValues(t, i, ss[0]) - - sss := MyStruct{} - has, err = testEngine.Get(&sss) - assert.NoError(t, err) - assert.True(t, has) - - sss.NameArray = []string{} - sss.MSS = map[string]string{} - cnt, err = testEngine.Delete(&sss) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) -} - -type Status struct { - Name string - Color string -} - -var ( - _ core.Conversion = &Status{} - Registed Status = Status{"Registed", "white"} - Approved Status = Status{"Approved", "green"} - Removed Status = Status{"Removed", "red"} - Statuses map[string]Status = map[string]Status{ - Registed.Name: Registed, - Approved.Name: Approved, - Removed.Name: Removed, - } -) - -func (s *Status) FromDB(bytes []byte) error { - if r, ok := Statuses[string(bytes)]; ok { - *s = r - return nil - } else { - return errors.New("no this data") - } -} - -func (s *Status) ToDB() ([]byte, error) { - return []byte(s.Name), nil -} - -type UserCus struct { - Id int64 - Name string - Status Status `xorm:"varchar(40)"` -} - -func TestCustomType2(t *testing.T) { - assert.NoError(t, prepareEngine()) - - var uc UserCus - err := testEngine.CreateTables(&uc) - assert.NoError(t, err) - - tableName := testEngine.TableName(&uc, true) - _, err = testEngine.Exec("delete from " + testEngine.Quote(tableName)) - assert.NoError(t, err) - - session := testEngine.NewSession() - defer session.Close() - - if testEngine.Dialect().DBType() == core.MSSQL { - err = session.Begin() - assert.NoError(t, err) - _, err = session.Exec("set IDENTITY_INSERT " + tableName + " on") - assert.NoError(t, err) - } - - cnt, err := session.Insert(&UserCus{1, "xlw", Registed}) - assert.NoError(t, err) - assert.EqualValues(t, 1, cnt) - - if testEngine.Dialect().DBType() == core.MSSQL { - err = session.Commit() - assert.NoError(t, err) - } - - user := UserCus{} - exist, err := testEngine.ID(1).Get(&user) - assert.NoError(t, err) - assert.True(t, exist) - - fmt.Println(user) - - users := make([]UserCus, 0) - err = testEngine.Where("`"+testEngine.GetColumnMapper().Obj2Table("Status")+"` = ?", "Registed").Find(&users) - assert.NoError(t, err) - assert.EqualValues(t, 1, len(users)) - - fmt.Println(users) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/xorm.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/xorm.go deleted file mode 100644 index 26d00d264..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/xorm.go +++ /dev/null @@ -1,126 +0,0 @@ -// Copyright 2015 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -// +build go1.8 - -package xorm - -import ( - "context" - "fmt" - "os" - "reflect" - "runtime" - "sync" - "time" - - "xorm.io/core" -) - -const ( - // Version show the xorm's version - Version string = "0.7.0.0504" -) - -func regDrvsNDialects() bool { - providedDrvsNDialects := map[string]struct { - dbType core.DbType - getDriver func() core.Driver - getDialect func() core.Dialect - }{ - "mssql": {"mssql", func() core.Driver { return &odbcDriver{} }, func() core.Dialect { return &mssql{} }}, - "odbc": {"mssql", func() core.Driver { return &odbcDriver{} }, func() core.Dialect { return &mssql{} }}, // !nashtsai! TODO change this when supporting MS Access - "mysql": {"mysql", func() core.Driver { return &mysqlDriver{} }, func() core.Dialect { return &mysql{} }}, - "mymysql": {"mysql", func() core.Driver { return &mymysqlDriver{} }, func() core.Dialect { return &mysql{} }}, - "postgres": {"postgres", func() core.Driver { return &pqDriver{} }, func() core.Dialect { return &postgres{} }}, - "pgx": {"postgres", func() core.Driver { return &pqDriverPgx{} }, func() core.Dialect { return &postgres{} }}, - "sqlite3": {"sqlite3", func() core.Driver { return &sqlite3Driver{} }, func() core.Dialect { return &sqlite3{} }}, - "oci8": {"oracle", func() core.Driver { return &oci8Driver{} }, func() core.Dialect { return &oracle{} }}, - "goracle": {"oracle", func() core.Driver { return &goracleDriver{} }, func() core.Dialect { return &oracle{} }}, - } - - for driverName, v := range providedDrvsNDialects { - if driver := core.QueryDriver(driverName); driver == nil { - core.RegisterDriver(driverName, v.getDriver()) - core.RegisterDialect(v.dbType, v.getDialect) - } - } - return true -} - -func close(engine *Engine) { - engine.Close() -} - -func init() { - regDrvsNDialects() -} - -// NewEngine new a db manager according to the parameter. Currently support four -// drivers -func NewEngine(driverName string, dataSourceName string) (*Engine, error) { - driver := core.QueryDriver(driverName) - if driver == nil { - return nil, fmt.Errorf("Unsupported driver name: %v", driverName) - } - - uri, err := driver.Parse(driverName, dataSourceName) - if err != nil { - return nil, err - } - - dialect := core.QueryDialect(uri.DbType) - if dialect == nil { - return nil, fmt.Errorf("Unsupported dialect type: %v", uri.DbType) - } - - db, err := core.Open(driverName, dataSourceName) - if err != nil { - return nil, err - } - - err = dialect.Init(db, uri, driverName, dataSourceName) - if err != nil { - return nil, err - } - - engine := &Engine{ - db: db, - dialect: dialect, - Tables: make(map[reflect.Type]*core.Table), - mutex: &sync.RWMutex{}, - TagIdentifier: "xorm", - TZLocation: time.Local, - tagHandlers: defaultTagHandlers, - cachers: make(map[string]core.Cacher), - defaultContext: context.Background(), - } - - if uri.DbType == core.SQLITE { - engine.DatabaseTZ = time.UTC - } else { - engine.DatabaseTZ = time.Local - } - - logger := NewSimpleLogger(os.Stdout) - logger.SetLevel(core.LOG_INFO) - engine.SetLogger(logger) - engine.SetMapper(core.NewCacheMapper(new(core.SnakeMapper))) - - runtime.SetFinalizer(engine, close) - - return engine, nil -} - -// NewEngineWithParams new a db manager with params. The params will be passed to dialect. -func NewEngineWithParams(driverName string, dataSourceName string, params map[string]string) (*Engine, error) { - engine, err := NewEngine(driverName, dataSourceName) - engine.dialect.SetParams(params) - return engine, err -} - -// Clone clone an engine -func (engine *Engine) Clone() (*Engine, error) { - return NewEngine(engine.DriverName(), engine.DataSourceName()) -} diff --git a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/xorm_test.go b/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/xorm_test.go deleted file mode 100644 index 21715256d..000000000 --- a/src/test/regress/go_driver_test/src/github.com/go-xorm/xorm/xorm_test.go +++ /dev/null @@ -1,195 +0,0 @@ -// Copyright 2018 The Xorm Authors. All rights reserved. -// Use of this source code is governed by a BSD-style -// license that can be found in the LICENSE file. - -package xorm - -import ( - "database/sql" - "flag" - "fmt" - "log" - "os" - "strings" - "testing" - - _ "github.com/denisenkom/go-mssqldb" - _ "github.com/go-sql-driver/mysql" - _ "github.com/lib/pq" - _ "github.com/mattn/go-sqlite3" - _ "github.com/ziutek/mymysql/godrv" - "xorm.io/core" -) - -var ( - testEngine EngineInterface - dbType string - connString string - - db = flag.String("db", "sqlite3", "the tested database") - showSQL = flag.Bool("show_sql", true, "show generated SQLs") - ptrConnStr = flag.String("conn_str", "./test.db?cache=shared&mode=rwc", "test database connection string") - mapType = flag.String("map_type", "snake", "indicate the name mapping") - cache = flag.Bool("cache", false, "if enable cache") - cluster = flag.Bool("cluster", false, "if this is a cluster") - splitter = flag.String("splitter", ";", "the splitter on connstr for cluster") - schema = flag.String("schema", "", "specify the schema") - ignoreSelectUpdate = flag.Bool("ignore_select_update", false, "ignore select update if implementation difference, only for tidb") - - tableMapper core.IMapper - colMapper core.IMapper -) - -func createEngine(dbType, connStr string) error { - if testEngine == nil { - var err error - - if !*cluster { - switch strings.ToLower(dbType) { - case core.MSSQL: - db, err := sql.Open(dbType, strings.Replace(connStr, "xorm_test", "master", -1)) - if err != nil { - return err - } - if _, err = db.Exec("If(db_id(N'xorm_test') IS NULL) BEGIN CREATE DATABASE xorm_test; END;"); err != nil { - return fmt.Errorf("db.Exec: %v", err) - } - db.Close() - *ignoreSelectUpdate = true - case core.POSTGRES: - db, err := sql.Open(dbType, connStr) - if err != nil { - return err - } - rows, err := db.Query(fmt.Sprintf("SELECT 1 FROM pg_database WHERE datname = 'xorm_test'")) - if err != nil { - return fmt.Errorf("db.Query: %v", err) - } - defer rows.Close() - - if !rows.Next() { - if _, err = db.Exec("CREATE DATABASE xorm_test"); err != nil { - return fmt.Errorf("CREATE DATABASE: %v", err) - } - } - if *schema != "" { - if _, err = db.Exec("CREATE SCHEMA IF NOT EXISTS " + *schema); err != nil { - return fmt.Errorf("CREATE SCHEMA: %v", err) - } - } - db.Close() - *ignoreSelectUpdate = true - case core.MYSQL: - db, err := sql.Open(dbType, strings.Replace(connStr, "xorm_test", "mysql", -1)) - if err != nil { - return err - } - if _, err = db.Exec("CREATE DATABASE IF NOT EXISTS xorm_test"); err != nil { - return fmt.Errorf("db.Exec: %v", err) - } - db.Close() - default: - *ignoreSelectUpdate = true - } - - testEngine, err = NewEngine(dbType, connStr) - } else { - testEngine, err = NewEngineGroup(dbType, strings.Split(connStr, *splitter)) - if dbType != "mysql" && dbType != "mymysql" { - *ignoreSelectUpdate = true - } - } - if err != nil { - return err - } - - if *schema != "" { - testEngine.SetSchema(*schema) - } - testEngine.ShowSQL(*showSQL) - testEngine.SetLogLevel(core.LOG_DEBUG) - if *cache { - cacher := NewLRUCacher(NewMemoryStore(), 100000) - testEngine.SetDefaultCacher(cacher) - } - - if len(*mapType) > 0 { - switch *mapType { - case "snake": - testEngine.SetMapper(core.SnakeMapper{}) - case "same": - testEngine.SetMapper(core.SameMapper{}) - case "gonic": - testEngine.SetMapper(core.LintGonicMapper) - } - } - } - - tableMapper = testEngine.GetTableMapper() - colMapper = testEngine.GetColumnMapper() - - tables, err := testEngine.DBMetas() - if err != nil { - return err - } - var tableNames = make([]interface{}, 0, len(tables)) - for _, table := range tables { - tableNames = append(tableNames, table.Name) - } - if err = testEngine.DropTables(tableNames...); err != nil { - return err - } - return nil -} - -func prepareEngine() error { - return createEngine(dbType, connString) -} - -func TestMain(m *testing.M) { - flag.Parse() - - dbType = *db - if *db == "sqlite3" { - if ptrConnStr == nil { - connString = "./test.db?cache=shared&mode=rwc" - } else { - connString = *ptrConnStr - } - } else { - if ptrConnStr == nil { - log.Fatal("you should indicate conn string") - return - } - connString = *ptrConnStr - } - - dbs := strings.Split(*db, "::") - conns := strings.Split(connString, "::") - - var res int - for i := 0; i < len(dbs); i++ { - dbType = dbs[i] - connString = conns[i] - testEngine = nil - fmt.Println("testing", dbType, connString) - - if err := prepareEngine(); err != nil { - log.Fatal(err) - return - } - - code := m.Run() - if code > 0 { - res = code - } - } - - os.Exit(res) -} - -func TestPing(t *testing.T) { - if err := testEngine.Ping(); err != nil { - t.Fatal(err) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/go.mod b/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/go.mod deleted file mode 100644 index c2513af77..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/lib/pg_libpq_test - -go 1.17 - -require github.com/lib/pq v0.0.0-00010101000000-000000000000 -replace github.com/lib/pq => ../../../github.com/lib/pq - - diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/go.sum b/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/go.sum deleted file mode 100644 index 76c36aa24..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/go.sum +++ /dev/null @@ -1,40 +0,0 @@ -github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -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/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= -github.com/go-xorm/sqlfiddle v0.0.0-20180821085327-62ce714f951a/go.mod h1:56xuuqnHyryaerycW3BfssRdxQstACi0Epw/yC5E2xM= -github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= -github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= -github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk= -github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= -github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= -github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= -golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= -golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= -golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= -golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= -golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= -google.golang.org/appengine v1.6.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= -xorm.io/builder v0.3.6/go.mod h1:LEFAPISnRzG+zxaxj2vPicRwz67BdhFreKg8yv8/TgU= -xorm.io/core v0.7.2-0.20190928055935-90aeac8d08eb/go.mod h1:jJfd0UAEzZ4t87nbQYtVjmqpIODugN6PD2D9E+dJvdM= diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgcom/diag.go b/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgcom/diag.go deleted file mode 100644 index 34157d6f6..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgcom/diag.go +++ /dev/null @@ -1,134 +0,0 @@ -package pgcom - -import ( - "fmt" - "log" - "os" - "runtime" - "strconv" - "strings" - "time" -) - -func init(){ - log.SetPrefix("TRACE: ") - log.SetFlags(log.Ldate | log.Ltime | log.Lmicroseconds | log.Llongfile) -} -func itoa(buf *[]byte, i int, wid int) { - // Assemble decimal in reverse order. - var b [20]byte - bp := len(b) - 1 - for i >= 10 || wid > 1 { - wid-- - q := i / 10 - b[bp] = byte('0' + i - q*10) - bp-- - i = q - } - // i < 10 - b[bp] = byte('0' + i) - *buf = append(*buf, b[bp:]...) -} - -func formatHeader(buf []byte, t time.Time, file string, line int) []byte{ - t = t.UTC() - year, month, day := t.Date() - itoa(&buf, year, 4) - buf = append(buf, '/') - itoa(&buf, int(month), 2) - buf = append(buf, '/') - itoa(&buf, day, 2) - buf = append(buf, ' ') - hour, min, sec := t.Clock() - itoa(&buf, hour, 2) - buf = append(buf, ':') - itoa(&buf, min, 2) - buf = append(buf, ':') - itoa(&buf, sec, 2) - buf = append(buf, '.') - itoa(&buf, t.Nanosecond()/1e3, 6) - buf = append(buf, ' ') - - short := file - for i := len(file) - 1; i > 0; i-- { - if file[i] == '/' { - short = file[i+1:] - break - } - } - file = short - buf = append(buf, file...) - buf = append(buf, ':') - itoa(&buf, line, -1) - return append(buf, ": "...) -} - -func CheckErr(res ...interface{}){ - for _,oriErr :=range res{ - if oriErr == nil{ - continue - } - switch oriErr.(type) { - case error: - err :=oriErr.(error) - s :=fmt.Sprintln(err) - _,file,line,ok:=runtime.Caller(1) - if ok { - info :="[CheckErr] " - buf :=make([]byte,0,1024) - buf=append(buf,info...) - buf = formatHeader(buf,time.Now(),file,line) - buf = append(buf, s...) - os.Stdout.Write(buf) - }else{ - fmt.Printf("%s %s",time.Now(),s) - } - os.Exit(2) - default: - } - } -} - - -func createNewFile(fileName string){ - err := os.Remove(fileName) - if err!=nil{ - log.Println(err) - } - fd,err:=os.Create(fileName) - if err!=nil{ - log.Fatal(err) - } - fd.Close() -} - -func GetGoid() int64 { - var ( - buf [64]byte - n = runtime.Stack(buf[:], false) - stk = strings.TrimPrefix(string(buf[:n]), "goroutine ") - ) - - idField := strings.Fields(stk)[0] - id, err := strconv.Atoi(idField) - if err != nil { - panic(fmt.Errorf("can not get goroutine id: %v", err)) - } - - return int64(id) -} - -func PrintType(a interface{}){ - switch a.(type) { - case int: - fmt.Println("type is int") - case string: - fmt.Println("type is string") - case float32: - fmt.Println("type is float32") - case float64: - fmt.Println("type is float64") - default: - fmt.Println("type is unknown type") - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgcom/getOp.go b/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgcom/getOp.go deleted file mode 100644 index 6e7198562..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgcom/getOp.go +++ /dev/null @@ -1,46 +0,0 @@ -package pgcom - -import ( - "math/rand" - "reflect" - "runtime" - "strings" - "time" -) - -func init(){ - rand.Seed(time.Now().UnixNano()) -} - -func GetRandomString(n int)string{ - str := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" - bytes :=[]byte(str) - result :=make([]byte,n) - for i:=0;i 0 { - return fields[size-1] - } - return "" -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgcom/mysql.go b/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgcom/mysql.go deleted file mode 100644 index 15cfda498..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgcom/mysql.go +++ /dev/null @@ -1,159 +0,0 @@ -package pgcom - -import ( - "database/sql" - "fmt" - _ "github.com/lib/pq" - "log" - "strconv" - "strings" -) - - -func PrintRowData(rows *sql.Rows){ - columns,err :=rows.Columns() - if err!=nil{ - log.Fatal("rows coulumns error",err) - } - cols:=len(columns) - - var scanResults = make([]interface{}, cols) - for i := 0; i < cols; i++ { - var s sql.NullString - scanResults[i] = &s - } - if err :=rows.Scan(scanResults...);err!=nil{ - log.Fatal("rows Scan error, ",err) - } - for i,key:=range columns{ - s := scanResults[i].(*sql.NullString) - if !s.Valid{ - fmt.Println(key+": NULL") - }else { - fmt.Println(key+": "+s.String) - } - } -} - -func IterScanRows(rows *sql.Rows)(idx int){ - for rows.Next(){ - idx++ - PrintRowData(rows) - } - return -} - -func IterScanDbTable(db *sql.DB, tname string)(idx int){ - sql :="select * from "+tname+" order by 1" - row,err:=db.Query(sql) - CheckErr(err) - return IterScanRows(row) -} - -func IterScanStmtTable(stmt *sql.Stmt, tname string)(idx int){ - sql :="select * from "+tname+" order by 1" - row,err:=stmt.Query(sql) - CheckErr(err) - return IterScanRows(row) -} - - -func IterScanTxTable(txn *sql.Tx, tname string)(idx int){ - sql :="select * from "+tname+" order by 1" - row,err := txn.Query(sql) - CheckErr(err) - return IterScanRows(row) -} - -type QueryInterface interface { - Query(query string, args ...interface{}) (*sql.Rows, error) -} - -func IterScanTable(sqlObject interface{}, tname string)(idx int){ - sql :="select * from "+tname+" order by 1" - if fQuery,ok:=sqlObject.(QueryInterface);ok{ - row,err := fQuery.Query(sql) - CheckErr(err) - return IterScanRows(row) - } else { - log.Fatal("cannot parse your input args") - } - return -1 -} - -func PrintQuery(db *sql.DB, sql string){ - rows,err:=db.Query(sql) - if err !=nil{ - //t.Fatal(err) - fmt.Println(err) - panic(err) - } - sqls :=strings.Split(sql,";") - tab_idx :=0 -LOOP: - tab_idx++ - fmt.Println("Query["+strconv.Itoa(tab_idx)+"]==> "+sqls[tab_idx-1]) - rowsCount := IterScanRows(rows) - fmt.Println("<==Query["+strconv.Itoa(tab_idx)+"]"+" has "+strconv.Itoa(rowsCount)+" rows.") - if rows.NextResultSet(){ - goto LOOP - } -} - - -func GetTableRowCounts(db *sql.DB,table string)(rows int){ - sql :="select count(*) from "+table; - err :=db.QueryRow(sql).Scan(&rows) - if err!=nil{ - log.Fatal("query "+table+" row counts error",err) - } - return -} -func PrintTableRowCounts(db *sql.DB,table string){ - fmt.Printf("%s : %d\n",table, GetTableRowCounts(db,table)) -} - -func TruncateTable(db *sql.DB,table string){ - sql :="select count(*) from "+table; - var rows int - err :=db.QueryRow(sql).Scan(&rows) - res,err:=db.Exec("truncate table "+table) - if err!=nil{ - log.Fatal("truncate table error,",err) - } - _,err = res.RowsAffected() - if err!=nil{ - log.Fatal("get rows affected error,",err) - } -} - -func CheckTabExists(db *sql.DB, schema,table string)bool{ - sql :="select count(*) from information_schema.columns where table_schema='"+schema+"' and table_name='"+table+"'" - var rowcount int - if err :=db.QueryRow(sql).Scan(&rowcount);err!=nil{ - fmt.Println(err) - return false - } - return rowcount==1 -} - -func PrintListenPort(db *sql.DB){ - var ips,port string - err :=db.QueryRow("select (select setting from pg_settings where name ='listen_addresses'), (select setting from pg_settings where name ='port')").Scan(&ips,&port) - if err!=nil{ - log.Fatal("PrintListenPort error,",err) - } - fmt.Println(ips,port) -} - -func SqlExec(db *sql.DB, sql string, args ...interface{}) { - r,err :=db.Exec(sql,args...) - if err !=nil{ - log.Fatal("sql["+sql+"] exec error,",err) - } - n,err:=r.RowsAffected() - if err!=nil{ - log.Fatal("sql["+sql+"] exec rows affect error,",err) - } - log.Println("sql["+sql+"] exec rows affect=",n) -} \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgpg_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgpg_test.go deleted file mode 100644 index aa4bfd760..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pg_libpq_test/pgpg_test.go +++ /dev/null @@ -1,69 +0,0 @@ -package pg_libpq_test - -import ( - "database/sql" - "fmt" - . "github.com/lib/pg_libpq_test/pgcom" - "log" - "math/rand" - "strconv" - "strings" - "sync" - "testing" -) - -// 为啥PG不支持绑定参数 -func insertTab2(db *sql.DB, thread_id,id_left, insert_rows int,wg *sync.WaitGroup){ - log.Printf("thread %v is begining...",thread_id) - tx,err :=db.Begin() - CheckErr(err) - stmt,err :=tx.Prepare("insert into people values(:1,:2,:3)") - CheckErr(err) - for i:=0;i init/root.crt - -----BEGIN CERTIFICATE----- - MIIEBjCCAu6gAwIBAgIJAPizR+OD14YnMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV - BAYTAlVTMQ8wDQYDVQQIDAZOZXZhZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgG - A1UECgwRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMMBXBxIENBMB4XDTIxMDkw - MjAxNTUwMloXDTMxMDkwMzAxNTUwMlowXjELMAkGA1UEBhMCVVMxDzANBgNVBAgM - Bk5ldmFkYTESMBAGA1UEBwwJTGFzIFZlZ2FzMRowGAYDVQQKDBFnaXRodWIuY29t - L2xpYi9wcTEOMAwGA1UEAwwFcHEgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw - ggEKAoIBAQDb9d6sjdU6GdibGrXRMOHREH3MRUS8T4TFqGgPEGVDP/V5bAZlBSGP - AN0o9DTyVLcbQpBt8zMTw9KeIzIIe5NIVkSmA16lw/YckGhOM+kZIkiDuE6qt5Ia - OQCRMdXkZ8ejG/JUu+rHU8FJZL8DE+jyYherzdjkeVAQ7JfzxAwW2Dl7T/47g337 - Pwmf17AEb8ibSqmXyUN7R5NhJQs+hvaYdNagzdx91E1H+qlyBvmiNeasUQljLvZ+ - Y8wAuU79neA+d09O4PBiYwV17rSP6SZCeGE3oLZviL/0KM9Xig88oB+2FmvQ6Zxa - L7SoBlqS+5pBZwpH7eee/wCIKAnJtMAJAgMBAAGjgcYwgcMwDwYDVR0TAQH/BAUw - AwEB/zAdBgNVHQ4EFgQUfIXEczahbcM2cFrwclJF7GbdajkwgZAGA1UdIwSBiDCB - hYAUfIXEczahbcM2cFrwclJF7GbdajmhYqRgMF4xCzAJBgNVBAYTAlVTMQ8wDQYD - VQQIDAZOZXZhZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgGA1UECgwRZ2l0aHVi - LmNvbS9saWIvcHExDjAMBgNVBAMMBXBxIENBggkA+LNH44PXhicwDQYJKoZIhvcN - AQELBQADggEBABFyGgSz2mHVJqYgX1Y+7P+MfKt83cV2uYDGYvXrLG2OGiCilVul - oTBG+8omIMSHOsQZvWMpA5H0tnnlQHrKpKpUyKkSL+Wv5GL0UtBmHX7mVRiaK2l4 - q2BjRaQUitp/FH4NSdXtVrMME5T1JBBZHsQkNL3cNRzRKwY/Vj5UGEDxDS7lILUC - e01L4oaK0iKQn4beALU+TvKoAHdPvoxpPpnhkF5ss9HmdcvRktJrKZemDJZswZ7/ - +omx8ZPIYYUH5VJJYYE88S7guAt+ZaKIUlel/t6xPbo2ZySFSg9u1uB99n+jTo3L - 1rAxFnN3FCX2jBqgP29xMVmisaN5k04UmyI= - -----END CERTIFICATE----- - CONF - cat < init/server.crt - -----BEGIN CERTIFICATE----- - MIIDqzCCApOgAwIBAgIJAPiewLrOyYipMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV - BAYTAlVTMQ8wDQYDVQQIDAZOZXZhZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgG - A1UECgwRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMMBXBxIENBMB4XDTIxMDkw - MjAxNTUwMloXDTMxMDkwMzAxNTUwMlowTjELMAkGA1UEBhMCVVMxDzANBgNVBAgM - Bk5ldmFkYTESMBAGA1UEBwwJTGFzIFZlZ2FzMRowGAYDVQQKDBFnaXRodWIuY29t - L2xpYi9wcTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKf6H4UzmANN - QiQJe92Mf3ETMYmpZKNNO9DPEHyNLIkag+XwMrBTdcCK0mLvsNCYpXuBN6703KCd - WAFOeMmj7gOsWtvjt5Xm6bRHLgegekXzcG/jDwq/wyzeDzr/YkITuIlG44Lf9lhY - FLwiHlHOWHnwrZaEh6aU//02aQkzyX5INeXl/3TZm2G2eIH6AOxOKOU27MUsyVSQ - 5DE+SDKGcRP4bElueeQWvxAXNMZYb7sVSDdfHI3zr32K4k/tC8x0fZJ5XN/dvl4t - 4N4MrYlmDO5XOrb/gQH1H4iu6+5EMDfZYab4fkThnNFdfFqu4/8Scv7KZ8mWqpKM - fGAjEPctQi0CAwEAAaN8MHowHQYDVR0OBBYEFENExPbmDyFB2AJUdbMvVyhlNPD5 - MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdEQQMMAqCCHBvc3RncmVzMCwG - CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkq - hkiG9w0BAQsFAAOCAQEAMRVbV8RiEsmp9HAtnVCZmRXMIbgPGrqjeSwk586s4K8v - BSqNCqxv6s5GfCRmDYiqSqeuCVDtUJS1HsTmbxVV7Ke71WMo+xHR1ICGKOa8WGCb - TGsuicG5QZXWaxeMOg4s0qpKmKko0d1aErdVsanU5dkrVS7D6729Ffnzu4lwApk6 - invAB67p8u7sojwqRq5ce0vRaG+YFylTrWomF9kauEb8gKbQ9Xc7QfX+h+UH/mq9 - Nvdj8LOHp6/82bZdnsYUOtV4lS1IA/qzeXpqBphxqfWabD1yLtkyJyImZKq8uIPp - 0CG4jhObPdWcCkXD6bg3QK3mhwlC79OtFgxWmldCRQ== - -----END CERTIFICATE----- - CONF - cat < init/server.key - -----BEGIN PRIVATE KEY----- - MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCn+h+FM5gDTUIk - CXvdjH9xEzGJqWSjTTvQzxB8jSyJGoPl8DKwU3XAitJi77DQmKV7gTeu9NygnVgB - TnjJo+4DrFrb47eV5um0Ry4HoHpF83Bv4w8Kv8Ms3g86/2JCE7iJRuOC3/ZYWBS8 - Ih5Rzlh58K2WhIemlP/9NmkJM8l+SDXl5f902ZthtniB+gDsTijlNuzFLMlUkOQx - PkgyhnET+GxJbnnkFr8QFzTGWG+7FUg3XxyN8699iuJP7QvMdH2SeVzf3b5eLeDe - DK2JZgzuVzq2/4EB9R+IruvuRDA32WGm+H5E4ZzRXXxaruP/EnL+ymfJlqqSjHxg - IxD3LUItAgMBAAECggEAOE2naQ9tIZYw2EFxikZApVcooJrtx6ropMnzHbx4NBB2 - K4mChAXFj184u77ZxmGT/jzGvFcI6LE0wWNbK0NOUV7hKZk/fPhkV3AQZrAMrAu4 - IVi7PwAd3JkmA8F8XuebUDA5rDGDsgL8GD9baFJA58abeLs9eMGyuF4XgOUh4bip - hgHa76O2rcDWNY5HZqqRslw75FzlYkB0PCts/UJxSswj70kTTihyOhDlrm2TnyxI - ne54UbGRrpfs9wiheSGLjDG81qZToBHQDwoAnjjZhu1VCaBISuGbgZrxyyRyqdnn - xPW+KczMv04XyvF7v6Pz+bUEppalLXGiXnH5UtWvZQKBgQDTPCdMpNE/hwlq4nAw - Kf42zIBWfbnMLVWYoeDiAOhtl9XAUAXn76xe6Rvo0qeAo67yejdbJfRq3HvGyw+q - 4PS8r9gXYmLYIPQxSoLL5+rFoBCN3qFippfjLB1j32mp7+15KjRj8FF2r6xIN8fu - XatSRsaqmvCWYLDRv/rbHnxwkwKBgQDLkyfFLF7BtwtPWKdqrwOM7ip1UKh+oDBS - vkCQ08aEFRBU7T3jChsx5GbaW6zmsSBwBwcrHclpSkz7n3aq19DDWObJR2p80Fma - rsXeIcvtEpkvT3pVX268P5d+XGs1kxgFunqTysG9yChW+xzcs5MdKBzuMPPn7rL8 - MKAzdar6PwKBgEypkzW8x3h/4Moa3k6MnwdyVs2NGaZheaRIc95yJ+jGZzxBjrMr - h+p2PbvU4BfO0AqOkpKRBtDVrlJqlggVVp04UHvEKE16QEW3Xhr0037f5cInX3j3 - Lz6yXwRFLAsR2aTUzWjL6jTh8uvO2s/GzQuyRh3a16Ar/WBShY+K0+zjAoGATnLT - xZjWnyHRmu8X/PWakamJ9RFzDPDgDlLAgM8LVgTj+UY/LgnL9wsEU6s2UuP5ExKy - QXxGDGwUhHar/SQTj+Pnc7Mwpw6HKSOmnnY5po8fNusSwml3O9XppEkrC0c236Y/ - 7EobJO5IFVTJh4cv7vFxTJzSsRL8KFD4uzvh+nMCgYEAqY8NBYtIgNJA2B6C6hHF - +bG7v46434ZHFfGTmMQwzE4taVg7YRnzYESAlvK4bAP5ZXR90n7GRGFhrXzoMZ38 - r0bw/q9rV+ReGda7/Bjf7ciCKiq0RODcHtf4IaskjPXCoQRGJtgCPLhWPfld6g9v - /HTvO96xv9e3eG/PKSPog94= - -----END PRIVATE KEY----- - CONF - cat < init/hba.sh - cat < /var/lib/postgresql/data/pg_hba.conf - local all all trust - host all postgres all trust - hostnossl all pqgossltest all reject - hostnossl all pqgosslcert all reject - hostssl all pqgossltest all trust - hostssl all pqgosslcert all cert - host all all all trust - EOF - CONF - sudo chown 999:999 ./init/* - sudo chmod 600 ./init/* - - - name: start postgres - run: | - docker run -d \ - --name pg \ - -p 5432:5432 \ - -v $(pwd)/init:/init \ - -e POSTGRES_PASSWORD=unused \ - -e POSTGRES_USER=postgres \ - postgres:${{ matrix.postgres }} \ - -c ssl=on \ - -c ssl_ca_file=/init/root.crt \ - -c ssl_cert_file=/init/server.crt \ - -c ssl_key_file=/init/server.key - - - name: configure postgres - run: | - n=0 - until [ "$n" -ge 10 ] - do - docker exec pg pg_isready -h localhost && break - n=$((n+1)) - echo waiting for postgres to be ready... - sleep 1 - done - docker exec pg bash /init/hba.sh - n=0 - until [ "$n" -ge 10 ] - do - docker exec pg su postgres -c '/usr/lib/postgresql/${{ matrix.postgres }}/bin/pg_ctl reload' && break - n=$((n+1)) - echo waiting for postgres to reload... - sleep 1 - done - - - name: setup hosts - run: echo '127.0.0.1 postgres' | sudo tee -a /etc/hosts - - - name: create db/roles - run: | - n=0 - until [ "$n" -ge 10 ] - do - docker exec pg pg_isready -h localhost && break - n=$((n+1)) - echo waiting for postgres to be ready... - sleep 1 - done - docker exec pg createdb -h localhost -U postgres pqgotest - docker exec pg createuser -h localhost -U postgres -DRS pqgossltest - docker exec pg createuser -h localhost -U postgres -DRS pqgosslcert - - - name: check out code into the Go module directory - uses: actions/checkout@v2 - - - name: set up go - uses: actions/setup-go@v2 - with: - go-version: ${{ matrix.go }} - id: go - - - name: set key perms - run: sudo chmod 600 certs/postgresql.key - - - name: run tests - env: - PGUSER: postgres - PGHOST: localhost - PGPORT: 5432 - PQGOSSLTESTS: 1 - PQSSLCERTTEST_PATH: certs - run: | - PQTEST_BINARY_PARAMETERS=no go test -race -v ./... - PQTEST_BINARY_PARAMETERS=yes go test -race -v ./... - - - name: install goimports - run: go get golang.org/x/tools/cmd/goimports - - - name: install staticcheck - run: | - wget https://github.com/dominikh/go-tools/releases/latest/download/staticcheck_linux_amd64.tar.gz -O - | tar -xz staticcheck - - - name: run goimports - run: | - goimports -d -e . | awk '{ print } END { exit NR == 0 ? 0 : 1 }' - - - name: run staticcheck - run: ./staticcheck/staticcheck -go 1.13 ./... - - - name: build - run: go build -v . diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/.gitignore b/src/test/regress/go_driver_test/src/github.com/lib/pq/.gitignore deleted file mode 100644 index 3243952a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/.gitignore +++ /dev/null @@ -1,6 +0,0 @@ -.db -*.test -*~ -*.swp -.idea -.vscode \ No newline at end of file diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/LICENSE.md b/src/test/regress/go_driver_test/src/github.com/lib/pq/LICENSE.md deleted file mode 100644 index 5773904a3..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/LICENSE.md +++ /dev/null @@ -1,8 +0,0 @@ -Copyright (c) 2011-2013, 'pq' Contributors -Portions Copyright (C) 2011 Blake Mizerany - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/README.md b/src/test/regress/go_driver_test/src/github.com/lib/pq/README.md deleted file mode 100644 index 126ee5d35..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/README.md +++ /dev/null @@ -1,36 +0,0 @@ -# pq - A pure Go postgres driver for Go's database/sql package - -[![GoDoc](https://godoc.org/github.com/lib/pq?status.svg)](https://pkg.go.dev/github.com/lib/pq?tab=doc) - -## Install - - go get github.com/lib/pq - -## Features - -* SSL -* Handles bad connections for `database/sql` -* Scan `time.Time` correctly (i.e. `timestamp[tz]`, `time[tz]`, `date`) -* Scan binary blobs correctly (i.e. `bytea`) -* Package for `hstore` support -* COPY FROM support -* pq.ParseURL for converting urls to connection strings for sql.Open. -* Many libpq compatible environment variables -* Unix socket support -* Notifications: `LISTEN`/`NOTIFY` -* pgpass support -* GSS (Kerberos) auth - -## Tests - -`go test` is used for testing. See [TESTS.md](TESTS.md) for more details. - -## Status - -This package is currently in maintenance mode, which means: -1. It generally does not accept new features. -2. It does accept bug fixes and version compatability changes provided by the community. -3. Maintainers usually do not resolve reported issues. -4. Community members are encouraged to help each other with reported issues. - -For users that require new features or reliable resolution of reported bugs, we recommend using [pgx](https://github.com/jackc/pgx) which is under active development. diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/TESTS.md b/src/test/regress/go_driver_test/src/github.com/lib/pq/TESTS.md deleted file mode 100644 index f05021115..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/TESTS.md +++ /dev/null @@ -1,33 +0,0 @@ -# Tests - -## Running Tests - -`go test` is used for testing. A running PostgreSQL -server is required, with the ability to log in. The -database to connect to test with is "pqgotest," on -"localhost" but these can be overridden using [environment -variables](https://www.postgresql.org/docs/9.3/static/libpq-envars.html). - -Example: - - PGHOST=/run/postgresql go test - -## Benchmarks - -A benchmark suite can be run as part of the tests: - - go test -bench . - -## Example setup (Docker) - -Run a postgres container: - -``` -docker run --expose 5432:5432 postgres -``` - -Run tests: - -``` -PGHOST=localhost PGPORT=5432 PGUSER=postgres PGSSLMODE=disable PGDATABASE=postgres go test -``` diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/array.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/array.go deleted file mode 100644 index 39c8f7e2e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/array.go +++ /dev/null @@ -1,895 +0,0 @@ -package pq - -import ( - "bytes" - "database/sql" - "database/sql/driver" - "encoding/hex" - "fmt" - "reflect" - "strconv" - "strings" -) - -var typeByteSlice = reflect.TypeOf([]byte{}) -var typeDriverValuer = reflect.TypeOf((*driver.Valuer)(nil)).Elem() -var typeSQLScanner = reflect.TypeOf((*sql.Scanner)(nil)).Elem() - -// Array returns the optimal driver.Valuer and sql.Scanner for an array or -// slice of any dimension. -// -// For example: -// db.Query(`SELECT * FROM t WHERE id = ANY($1)`, pq.Array([]int{235, 401})) -// -// var x []sql.NullInt64 -// db.QueryRow(`SELECT ARRAY[235, 401]`).Scan(pq.Array(&x)) -// -// Scanning multi-dimensional arrays is not supported. Arrays where the lower -// bound is not one (such as `[0:0]={1}') are not supported. -func Array(a interface{}) interface { - driver.Valuer - sql.Scanner -} { - switch a := a.(type) { - case []bool: - return (*BoolArray)(&a) - case []float64: - return (*Float64Array)(&a) - case []float32: - return (*Float32Array)(&a) - case []int64: - return (*Int64Array)(&a) - case []int32: - return (*Int32Array)(&a) - case []string: - return (*StringArray)(&a) - case [][]byte: - return (*ByteaArray)(&a) - - case *[]bool: - return (*BoolArray)(a) - case *[]float64: - return (*Float64Array)(a) - case *[]float32: - return (*Float32Array)(a) - case *[]int64: - return (*Int64Array)(a) - case *[]int32: - return (*Int32Array)(a) - case *[]string: - return (*StringArray)(a) - case *[][]byte: - return (*ByteaArray)(a) - } - - return GenericArray{a} -} - -// ArrayDelimiter may be optionally implemented by driver.Valuer or sql.Scanner -// to override the array delimiter used by GenericArray. -type ArrayDelimiter interface { - // ArrayDelimiter returns the delimiter character(s) for this element's type. - ArrayDelimiter() string -} - -// BoolArray represents a one-dimensional array of the PostgreSQL boolean type. -type BoolArray []bool - -// Scan implements the sql.Scanner interface. -func (a *BoolArray) Scan(src interface{}) error { - switch src := src.(type) { - case []byte: - return a.scanBytes(src) - case string: - return a.scanBytes([]byte(src)) - case nil: - *a = nil - return nil - } - - return fmt.Errorf("pq: cannot convert %T to BoolArray", src) -} - -func (a *BoolArray) scanBytes(src []byte) error { - elems, err := scanLinearArray(src, []byte{','}, "BoolArray") - if err != nil { - return err - } - if *a != nil && len(elems) == 0 { - *a = (*a)[:0] - } else { - b := make(BoolArray, len(elems)) - for i, v := range elems { - if len(v) != 1 { - return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v) - } - switch v[0] { - case 't': - b[i] = true - case 'f': - b[i] = false - default: - return fmt.Errorf("pq: could not parse boolean array index %d: invalid boolean %q", i, v) - } - } - *a = b - } - return nil -} - -// Value implements the driver.Valuer interface. -func (a BoolArray) Value() (driver.Value, error) { - if a == nil { - return nil, nil - } - - if n := len(a); n > 0 { - // There will be exactly two curly brackets, N bytes of values, - // and N-1 bytes of delimiters. - b := make([]byte, 1+2*n) - - for i := 0; i < n; i++ { - b[2*i] = ',' - if a[i] { - b[1+2*i] = 't' - } else { - b[1+2*i] = 'f' - } - } - - b[0] = '{' - b[2*n] = '}' - - return string(b), nil - } - - return "{}", nil -} - -// ByteaArray represents a one-dimensional array of the PostgreSQL bytea type. -type ByteaArray [][]byte - -// Scan implements the sql.Scanner interface. -func (a *ByteaArray) Scan(src interface{}) error { - switch src := src.(type) { - case []byte: - return a.scanBytes(src) - case string: - return a.scanBytes([]byte(src)) - case nil: - *a = nil - return nil - } - - return fmt.Errorf("pq: cannot convert %T to ByteaArray", src) -} - -func (a *ByteaArray) scanBytes(src []byte) error { - elems, err := scanLinearArray(src, []byte{','}, "ByteaArray") - if err != nil { - return err - } - if *a != nil && len(elems) == 0 { - *a = (*a)[:0] - } else { - b := make(ByteaArray, len(elems)) - for i, v := range elems { - b[i], err = parseBytea(v) - if err != nil { - return fmt.Errorf("could not parse bytea array index %d: %s", i, err.Error()) - } - } - *a = b - } - return nil -} - -// Value implements the driver.Valuer interface. It uses the "hex" format which -// is only supported on PostgreSQL 9.0 or newer. -func (a ByteaArray) Value() (driver.Value, error) { - if a == nil { - return nil, nil - } - - if n := len(a); n > 0 { - // There will be at least two curly brackets, 2*N bytes of quotes, - // 3*N bytes of hex formatting, and N-1 bytes of delimiters. - size := 1 + 6*n - for _, x := range a { - size += hex.EncodedLen(len(x)) - } - - b := make([]byte, size) - - for i, s := 0, b; i < n; i++ { - o := copy(s, `,"\\x`) - o += hex.Encode(s[o:], a[i]) - s[o] = '"' - s = s[o+1:] - } - - b[0] = '{' - b[size-1] = '}' - - return string(b), nil - } - - return "{}", nil -} - -// Float64Array represents a one-dimensional array of the PostgreSQL double -// precision type. -type Float64Array []float64 - -// Scan implements the sql.Scanner interface. -func (a *Float64Array) Scan(src interface{}) error { - switch src := src.(type) { - case []byte: - return a.scanBytes(src) - case string: - return a.scanBytes([]byte(src)) - case nil: - *a = nil - return nil - } - - return fmt.Errorf("pq: cannot convert %T to Float64Array", src) -} - -func (a *Float64Array) scanBytes(src []byte) error { - elems, err := scanLinearArray(src, []byte{','}, "Float64Array") - if err != nil { - return err - } - if *a != nil && len(elems) == 0 { - *a = (*a)[:0] - } else { - b := make(Float64Array, len(elems)) - for i, v := range elems { - if b[i], err = strconv.ParseFloat(string(v), 64); err != nil { - return fmt.Errorf("pq: parsing array element index %d: %v", i, err) - } - } - *a = b - } - return nil -} - -// Value implements the driver.Valuer interface. -func (a Float64Array) Value() (driver.Value, error) { - if a == nil { - return nil, nil - } - - if n := len(a); n > 0 { - // There will be at least two curly brackets, N bytes of values, - // and N-1 bytes of delimiters. - b := make([]byte, 1, 1+2*n) - b[0] = '{' - - b = strconv.AppendFloat(b, a[0], 'f', -1, 64) - for i := 1; i < n; i++ { - b = append(b, ',') - b = strconv.AppendFloat(b, a[i], 'f', -1, 64) - } - - return string(append(b, '}')), nil - } - - return "{}", nil -} - -// Float32Array represents a one-dimensional array of the PostgreSQL double -// precision type. -type Float32Array []float32 - -// Scan implements the sql.Scanner interface. -func (a *Float32Array) Scan(src interface{}) error { - switch src := src.(type) { - case []byte: - return a.scanBytes(src) - case string: - return a.scanBytes([]byte(src)) - case nil: - *a = nil - return nil - } - - return fmt.Errorf("pq: cannot convert %T to Float32Array", src) -} - -func (a *Float32Array) scanBytes(src []byte) error { - elems, err := scanLinearArray(src, []byte{','}, "Float32Array") - if err != nil { - return err - } - if *a != nil && len(elems) == 0 { - *a = (*a)[:0] - } else { - b := make(Float32Array, len(elems)) - for i, v := range elems { - var x float64 - if x, err = strconv.ParseFloat(string(v), 32); err != nil { - return fmt.Errorf("pq: parsing array element index %d: %v", i, err) - } - b[i] = float32(x) - } - *a = b - } - return nil -} - -// Value implements the driver.Valuer interface. -func (a Float32Array) Value() (driver.Value, error) { - if a == nil { - return nil, nil - } - - if n := len(a); n > 0 { - // There will be at least two curly brackets, N bytes of values, - // and N-1 bytes of delimiters. - b := make([]byte, 1, 1+2*n) - b[0] = '{' - - b = strconv.AppendFloat(b, float64(a[0]), 'f', -1, 32) - for i := 1; i < n; i++ { - b = append(b, ',') - b = strconv.AppendFloat(b, float64(a[i]), 'f', -1, 32) - } - - return string(append(b, '}')), nil - } - - return "{}", nil -} - -// GenericArray implements the driver.Valuer and sql.Scanner interfaces for -// an array or slice of any dimension. -type GenericArray struct{ A interface{} } - -func (GenericArray) evaluateDestination(rt reflect.Type) (reflect.Type, func([]byte, reflect.Value) error, string) { - var assign func([]byte, reflect.Value) error - var del = "," - - // TODO calculate the assign function for other types - // TODO repeat this section on the element type of arrays or slices (multidimensional) - { - if reflect.PtrTo(rt).Implements(typeSQLScanner) { - // dest is always addressable because it is an element of a slice. - assign = func(src []byte, dest reflect.Value) (err error) { - ss := dest.Addr().Interface().(sql.Scanner) - if src == nil { - err = ss.Scan(nil) - } else { - err = ss.Scan(src) - } - return - } - goto FoundType - } - - assign = func([]byte, reflect.Value) error { - return fmt.Errorf("pq: scanning to %s is not implemented; only sql.Scanner", rt) - } - } - -FoundType: - - if ad, ok := reflect.Zero(rt).Interface().(ArrayDelimiter); ok { - del = ad.ArrayDelimiter() - } - - return rt, assign, del -} - -// Scan implements the sql.Scanner interface. -func (a GenericArray) Scan(src interface{}) error { - dpv := reflect.ValueOf(a.A) - switch { - case dpv.Kind() != reflect.Ptr: - return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A) - case dpv.IsNil(): - return fmt.Errorf("pq: destination %T is nil", a.A) - } - - dv := dpv.Elem() - switch dv.Kind() { - case reflect.Slice: - case reflect.Array: - default: - return fmt.Errorf("pq: destination %T is not a pointer to array or slice", a.A) - } - - switch src := src.(type) { - case []byte: - return a.scanBytes(src, dv) - case string: - return a.scanBytes([]byte(src), dv) - case nil: - if dv.Kind() == reflect.Slice { - dv.Set(reflect.Zero(dv.Type())) - return nil - } - } - - return fmt.Errorf("pq: cannot convert %T to %s", src, dv.Type()) -} - -func (a GenericArray) scanBytes(src []byte, dv reflect.Value) error { - dtype, assign, del := a.evaluateDestination(dv.Type().Elem()) - dims, elems, err := parseArray(src, []byte(del)) - if err != nil { - return err - } - - // TODO allow multidimensional - - if len(dims) > 1 { - return fmt.Errorf("pq: scanning from multidimensional ARRAY%s is not implemented", - strings.Replace(fmt.Sprint(dims), " ", "][", -1)) - } - - // Treat a zero-dimensional array like an array with a single dimension of zero. - if len(dims) == 0 { - dims = append(dims, 0) - } - - for i, rt := 0, dv.Type(); i < len(dims); i, rt = i+1, rt.Elem() { - switch rt.Kind() { - case reflect.Slice: - case reflect.Array: - if rt.Len() != dims[i] { - return fmt.Errorf("pq: cannot convert ARRAY%s to %s", - strings.Replace(fmt.Sprint(dims), " ", "][", -1), dv.Type()) - } - default: - // TODO handle multidimensional - } - } - - values := reflect.MakeSlice(reflect.SliceOf(dtype), len(elems), len(elems)) - for i, e := range elems { - if err := assign(e, values.Index(i)); err != nil { - return fmt.Errorf("pq: parsing array element index %d: %v", i, err) - } - } - - // TODO handle multidimensional - - switch dv.Kind() { - case reflect.Slice: - dv.Set(values.Slice(0, dims[0])) - case reflect.Array: - for i := 0; i < dims[0]; i++ { - dv.Index(i).Set(values.Index(i)) - } - } - - return nil -} - -// Value implements the driver.Valuer interface. -func (a GenericArray) Value() (driver.Value, error) { - if a.A == nil { - return nil, nil - } - - rv := reflect.ValueOf(a.A) - - switch rv.Kind() { - case reflect.Slice: - if rv.IsNil() { - return nil, nil - } - case reflect.Array: - default: - return nil, fmt.Errorf("pq: Unable to convert %T to array", a.A) - } - - if n := rv.Len(); n > 0 { - // There will be at least two curly brackets, N bytes of values, - // and N-1 bytes of delimiters. - b := make([]byte, 0, 1+2*n) - - b, _, err := appendArray(b, rv, n) - return string(b), err - } - - return "{}", nil -} - -// Int64Array represents a one-dimensional array of the PostgreSQL integer types. -type Int64Array []int64 - -// Scan implements the sql.Scanner interface. -func (a *Int64Array) Scan(src interface{}) error { - switch src := src.(type) { - case []byte: - return a.scanBytes(src) - case string: - return a.scanBytes([]byte(src)) - case nil: - *a = nil - return nil - } - - return fmt.Errorf("pq: cannot convert %T to Int64Array", src) -} - -func (a *Int64Array) scanBytes(src []byte) error { - elems, err := scanLinearArray(src, []byte{','}, "Int64Array") - if err != nil { - return err - } - if *a != nil && len(elems) == 0 { - *a = (*a)[:0] - } else { - b := make(Int64Array, len(elems)) - for i, v := range elems { - if b[i], err = strconv.ParseInt(string(v), 10, 64); err != nil { - return fmt.Errorf("pq: parsing array element index %d: %v", i, err) - } - } - *a = b - } - return nil -} - -// Value implements the driver.Valuer interface. -func (a Int64Array) Value() (driver.Value, error) { - if a == nil { - return nil, nil - } - - if n := len(a); n > 0 { - // There will be at least two curly brackets, N bytes of values, - // and N-1 bytes of delimiters. - b := make([]byte, 1, 1+2*n) - b[0] = '{' - - b = strconv.AppendInt(b, a[0], 10) - for i := 1; i < n; i++ { - b = append(b, ',') - b = strconv.AppendInt(b, a[i], 10) - } - - return string(append(b, '}')), nil - } - - return "{}", nil -} - -// Int32Array represents a one-dimensional array of the PostgreSQL integer types. -type Int32Array []int32 - -// Scan implements the sql.Scanner interface. -func (a *Int32Array) Scan(src interface{}) error { - switch src := src.(type) { - case []byte: - return a.scanBytes(src) - case string: - return a.scanBytes([]byte(src)) - case nil: - *a = nil - return nil - } - - return fmt.Errorf("pq: cannot convert %T to Int32Array", src) -} - -func (a *Int32Array) scanBytes(src []byte) error { - elems, err := scanLinearArray(src, []byte{','}, "Int32Array") - if err != nil { - return err - } - if *a != nil && len(elems) == 0 { - *a = (*a)[:0] - } else { - b := make(Int32Array, len(elems)) - for i, v := range elems { - x, err := strconv.ParseInt(string(v), 10, 32) - if err != nil { - return fmt.Errorf("pq: parsing array element index %d: %v", i, err) - } - b[i] = int32(x) - } - *a = b - } - return nil -} - -// Value implements the driver.Valuer interface. -func (a Int32Array) Value() (driver.Value, error) { - if a == nil { - return nil, nil - } - - if n := len(a); n > 0 { - // There will be at least two curly brackets, N bytes of values, - // and N-1 bytes of delimiters. - b := make([]byte, 1, 1+2*n) - b[0] = '{' - - b = strconv.AppendInt(b, int64(a[0]), 10) - for i := 1; i < n; i++ { - b = append(b, ',') - b = strconv.AppendInt(b, int64(a[i]), 10) - } - - return string(append(b, '}')), nil - } - - return "{}", nil -} - -// StringArray represents a one-dimensional array of the PostgreSQL character types. -type StringArray []string - -// Scan implements the sql.Scanner interface. -func (a *StringArray) Scan(src interface{}) error { - switch src := src.(type) { - case []byte: - return a.scanBytes(src) - case string: - return a.scanBytes([]byte(src)) - case nil: - *a = nil - return nil - } - - return fmt.Errorf("pq: cannot convert %T to StringArray", src) -} - -func (a *StringArray) scanBytes(src []byte) error { - elems, err := scanLinearArray(src, []byte{','}, "StringArray") - if err != nil { - return err - } - if *a != nil && len(elems) == 0 { - *a = (*a)[:0] - } else { - b := make(StringArray, len(elems)) - for i, v := range elems { - if b[i] = string(v); v == nil { - return fmt.Errorf("pq: parsing array element index %d: cannot convert nil to string", i) - } - } - *a = b - } - return nil -} - -// Value implements the driver.Valuer interface. -func (a StringArray) Value() (driver.Value, error) { - if a == nil { - return nil, nil - } - - if n := len(a); n > 0 { - // There will be at least two curly brackets, 2*N bytes of quotes, - // and N-1 bytes of delimiters. - b := make([]byte, 1, 1+3*n) - b[0] = '{' - - b = appendArrayQuotedBytes(b, []byte(a[0])) - for i := 1; i < n; i++ { - b = append(b, ',') - b = appendArrayQuotedBytes(b, []byte(a[i])) - } - - return string(append(b, '}')), nil - } - - return "{}", nil -} - -// appendArray appends rv to the buffer, returning the extended buffer and -// the delimiter used between elements. -// -// It panics when n <= 0 or rv's Kind is not reflect.Array nor reflect.Slice. -func appendArray(b []byte, rv reflect.Value, n int) ([]byte, string, error) { - var del string - var err error - - b = append(b, '{') - - if b, del, err = appendArrayElement(b, rv.Index(0)); err != nil { - return b, del, err - } - - for i := 1; i < n; i++ { - b = append(b, del...) - if b, del, err = appendArrayElement(b, rv.Index(i)); err != nil { - return b, del, err - } - } - - return append(b, '}'), del, nil -} - -// appendArrayElement appends rv to the buffer, returning the extended buffer -// and the delimiter to use before the next element. -// -// When rv's Kind is neither reflect.Array nor reflect.Slice, it is converted -// using driver.DefaultParameterConverter and the resulting []byte or string -// is double-quoted. -// -// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO -func appendArrayElement(b []byte, rv reflect.Value) ([]byte, string, error) { - if k := rv.Kind(); k == reflect.Array || k == reflect.Slice { - if t := rv.Type(); t != typeByteSlice && !t.Implements(typeDriverValuer) { - if n := rv.Len(); n > 0 { - return appendArray(b, rv, n) - } - - return b, "", nil - } - } - - var del = "," - var err error - var iv interface{} = rv.Interface() - - if ad, ok := iv.(ArrayDelimiter); ok { - del = ad.ArrayDelimiter() - } - - if iv, err = driver.DefaultParameterConverter.ConvertValue(iv); err != nil { - return b, del, err - } - - switch v := iv.(type) { - case nil: - return append(b, "NULL"...), del, nil - case []byte: - return appendArrayQuotedBytes(b, v), del, nil - case string: - return appendArrayQuotedBytes(b, []byte(v)), del, nil - } - - b, err = appendValue(b, iv) - return b, del, err -} - -func appendArrayQuotedBytes(b, v []byte) []byte { - b = append(b, '"') - for { - i := bytes.IndexAny(v, `"\`) - if i < 0 { - b = append(b, v...) - break - } - if i > 0 { - b = append(b, v[:i]...) - } - b = append(b, '\\', v[i]) - v = v[i+1:] - } - return append(b, '"') -} - -func appendValue(b []byte, v driver.Value) ([]byte, error) { - return append(b, encode(nil, v, 0)...), nil -} - -// parseArray extracts the dimensions and elements of an array represented in -// text format. Only representations emitted by the backend are supported. -// Notably, whitespace around brackets and delimiters is significant, and NULL -// is case-sensitive. -// -// See http://www.postgresql.org/docs/current/static/arrays.html#ARRAYS-IO -func parseArray(src, del []byte) (dims []int, elems [][]byte, err error) { - var depth, i int - - if len(src) < 1 || src[0] != '{' { - return nil, nil, fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '{', 0) - } - -Open: - for i < len(src) { - switch src[i] { - case '{': - depth++ - i++ - case '}': - elems = make([][]byte, 0) - goto Close - default: - break Open - } - } - dims = make([]int, i) - -Element: - for i < len(src) { - switch src[i] { - case '{': - if depth == len(dims) { - break Element - } - depth++ - dims[depth-1] = 0 - i++ - case '"': - var elem = []byte{} - var escape bool - for i++; i < len(src); i++ { - if escape { - elem = append(elem, src[i]) - escape = false - } else { - switch src[i] { - default: - elem = append(elem, src[i]) - case '\\': - escape = true - case '"': - elems = append(elems, elem) - i++ - break Element - } - } - } - default: - for start := i; i < len(src); i++ { - if bytes.HasPrefix(src[i:], del) || src[i] == '}' { - elem := src[start:i] - if len(elem) == 0 { - return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) - } - if bytes.Equal(elem, []byte("NULL")) { - elem = nil - } - elems = append(elems, elem) - break Element - } - } - } - } - - for i < len(src) { - if bytes.HasPrefix(src[i:], del) && depth > 0 { - dims[depth-1]++ - i += len(del) - goto Element - } else if src[i] == '}' && depth > 0 { - dims[depth-1]++ - depth-- - i++ - } else { - return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) - } - } - -Close: - for i < len(src) { - if src[i] == '}' && depth > 0 { - depth-- - i++ - } else { - return nil, nil, fmt.Errorf("pq: unable to parse array; unexpected %q at offset %d", src[i], i) - } - } - if depth > 0 { - err = fmt.Errorf("pq: unable to parse array; expected %q at offset %d", '}', i) - } - if err == nil { - for _, d := range dims { - if (len(elems) % d) != 0 { - err = fmt.Errorf("pq: multidimensional arrays must have elements with matching dimensions") - } - } - } - return -} - -func scanLinearArray(src, del []byte, typ string) (elems [][]byte, err error) { - dims, elems, err := parseArray(src, del) - if err != nil { - return nil, err - } - if len(dims) > 1 { - return nil, fmt.Errorf("pq: cannot convert ARRAY%s to %s", strings.Replace(fmt.Sprint(dims), " ", "][", -1), typ) - } - return elems, err -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/array_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/array_test.go deleted file mode 100644 index 5ca9f7a55..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/array_test.go +++ /dev/null @@ -1,1652 +0,0 @@ -package pq - -import ( - "bytes" - "database/sql" - "database/sql/driver" - "math/rand" - "reflect" - "strings" - "testing" -) - -func TestParseArray(t *testing.T) { - for _, tt := range []struct { - input string - delim string - dims []int - elems [][]byte - }{ - {`{}`, `,`, nil, [][]byte{}}, - {`{NULL}`, `,`, []int{1}, [][]byte{nil}}, - {`{a}`, `,`, []int{1}, [][]byte{{'a'}}}, - {`{a,b}`, `,`, []int{2}, [][]byte{{'a'}, {'b'}}}, - {`{{a,b}}`, `,`, []int{1, 2}, [][]byte{{'a'}, {'b'}}}, - {`{{a},{b}}`, `,`, []int{2, 1}, [][]byte{{'a'}, {'b'}}}, - {`{{{a,b},{c,d},{e,f}}}`, `,`, []int{1, 3, 2}, [][]byte{ - {'a'}, {'b'}, {'c'}, {'d'}, {'e'}, {'f'}, - }}, - {`{""}`, `,`, []int{1}, [][]byte{{}}}, - {`{","}`, `,`, []int{1}, [][]byte{{','}}}, - {`{",",","}`, `,`, []int{2}, [][]byte{{','}, {','}}}, - {`{{",",","}}`, `,`, []int{1, 2}, [][]byte{{','}, {','}}}, - {`{{","},{","}}`, `,`, []int{2, 1}, [][]byte{{','}, {','}}}, - {`{{{",",","},{",",","},{",",","}}}`, `,`, []int{1, 3, 2}, [][]byte{ - {','}, {','}, {','}, {','}, {','}, {','}, - }}, - {`{"\"}"}`, `,`, []int{1}, [][]byte{{'"', '}'}}}, - {`{"\"","\""}`, `,`, []int{2}, [][]byte{{'"'}, {'"'}}}, - {`{{"\"","\""}}`, `,`, []int{1, 2}, [][]byte{{'"'}, {'"'}}}, - {`{{"\""},{"\""}}`, `,`, []int{2, 1}, [][]byte{{'"'}, {'"'}}}, - {`{{{"\"","\""},{"\"","\""},{"\"","\""}}}`, `,`, []int{1, 3, 2}, [][]byte{ - {'"'}, {'"'}, {'"'}, {'"'}, {'"'}, {'"'}, - }}, - {`{axyzb}`, `xyz`, []int{2}, [][]byte{{'a'}, {'b'}}}, - } { - dims, elems, err := parseArray([]byte(tt.input), []byte(tt.delim)) - - if err != nil { - t.Fatalf("Expected no error for %q, got %q", tt.input, err) - } - if !reflect.DeepEqual(dims, tt.dims) { - t.Errorf("Expected %v dimensions for %q, got %v", tt.dims, tt.input, dims) - } - if !reflect.DeepEqual(elems, tt.elems) { - t.Errorf("Expected %v elements for %q, got %v", tt.elems, tt.input, elems) - } - } -} - -func TestParseArrayError(t *testing.T) { - for _, tt := range []struct { - input, err string - }{ - {``, "expected '{' at offset 0"}, - {`x`, "expected '{' at offset 0"}, - {`}`, "expected '{' at offset 0"}, - {`{`, "expected '}' at offset 1"}, - {`{{}`, "expected '}' at offset 3"}, - {`{}}`, "unexpected '}' at offset 2"}, - {`{,}`, "unexpected ',' at offset 1"}, - {`{,x}`, "unexpected ',' at offset 1"}, - {`{x,}`, "unexpected '}' at offset 3"}, - {`{x,{`, "unexpected '{' at offset 3"}, - {`{x},`, "unexpected ',' at offset 3"}, - {`{x}}`, "unexpected '}' at offset 3"}, - {`{{x}`, "expected '}' at offset 4"}, - {`{""x}`, "unexpected 'x' at offset 3"}, - {`{{a},{b,c}}`, "multidimensional arrays must have elements with matching dimensions"}, - } { - _, _, err := parseArray([]byte(tt.input), []byte{','}) - - if err == nil { - t.Fatalf("Expected error for %q, got none", tt.input) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err) - } - } -} - -func TestArrayScanner(t *testing.T) { - var s sql.Scanner = Array(&[]bool{}) - if _, ok := s.(*BoolArray); !ok { - t.Errorf("Expected *BoolArray, got %T", s) - } - - s = Array(&[]float64{}) - if _, ok := s.(*Float64Array); !ok { - t.Errorf("Expected *Float64Array, got %T", s) - } - - s = Array(&[]int64{}) - if _, ok := s.(*Int64Array); !ok { - t.Errorf("Expected *Int64Array, got %T", s) - } - - s = Array(&[]float32{}) - if _, ok := s.(*Float32Array); !ok { - t.Errorf("Expected *Float32Array, got %T", s) - } - - s = Array(&[]int32{}) - if _, ok := s.(*Int32Array); !ok { - t.Errorf("Expected *Int32Array, got %T", s) - } - - s = Array(&[]string{}) - if _, ok := s.(*StringArray); !ok { - t.Errorf("Expected *StringArray, got %T", s) - } - - s = Array(&[][]byte{}) - if _, ok := s.(*ByteaArray); !ok { - t.Errorf("Expected *ByteaArray, got %T", s) - } - - for _, tt := range []interface{}{ - &[]sql.Scanner{}, - &[][]bool{}, - &[][]float64{}, - &[][]int64{}, - &[][]float32{}, - &[][]int32{}, - &[][]string{}, - } { - s = Array(tt) - if _, ok := s.(GenericArray); !ok { - t.Errorf("Expected GenericArray for %T, got %T", tt, s) - } - } -} - -func TestArrayValuer(t *testing.T) { - var v driver.Valuer = Array([]bool{}) - if _, ok := v.(*BoolArray); !ok { - t.Errorf("Expected *BoolArray, got %T", v) - } - - v = Array([]float64{}) - if _, ok := v.(*Float64Array); !ok { - t.Errorf("Expected *Float64Array, got %T", v) - } - - v = Array([]int64{}) - if _, ok := v.(*Int64Array); !ok { - t.Errorf("Expected *Int64Array, got %T", v) - } - - v = Array([]float32{}) - if _, ok := v.(*Float32Array); !ok { - t.Errorf("Expected *Float32Array, got %T", v) - } - - v = Array([]int32{}) - if _, ok := v.(*Int32Array); !ok { - t.Errorf("Expected *Int32Array, got %T", v) - } - - v = Array([]string{}) - if _, ok := v.(*StringArray); !ok { - t.Errorf("Expected *StringArray, got %T", v) - } - - v = Array([][]byte{}) - if _, ok := v.(*ByteaArray); !ok { - t.Errorf("Expected *ByteaArray, got %T", v) - } - - for _, tt := range []interface{}{ - nil, - []driver.Value{}, - [][]bool{}, - [][]float64{}, - [][]int64{}, - [][]float32{}, - [][]int32{}, - [][]string{}, - } { - v = Array(tt) - if _, ok := v.(GenericArray); !ok { - t.Errorf("Expected GenericArray for %T, got %T", tt, v) - } - } -} - -func TestBoolArrayScanUnsupported(t *testing.T) { - var arr BoolArray - err := arr.Scan(1) - - if err == nil { - t.Fatal("Expected error when scanning from int") - } - if !strings.Contains(err.Error(), "int to BoolArray") { - t.Errorf("Expected type to be mentioned when scanning, got %q", err) - } -} - -func TestBoolArrayScanEmpty(t *testing.T) { - var arr BoolArray - err := arr.Scan(`{}`) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr == nil || len(arr) != 0 { - t.Errorf("Expected empty, got %#v", arr) - } -} - -func TestBoolArrayScanNil(t *testing.T) { - arr := BoolArray{true, true, true} - err := arr.Scan(nil) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr != nil { - t.Errorf("Expected nil, got %+v", arr) - } -} - -var BoolArrayStringTests = []struct { - str string - arr BoolArray -}{ - {`{}`, BoolArray{}}, - {`{t}`, BoolArray{true}}, - {`{f,t}`, BoolArray{false, true}}, -} - -func TestBoolArrayScanBytes(t *testing.T) { - for _, tt := range BoolArrayStringTests { - bytes := []byte(tt.str) - arr := BoolArray{true, true, true} - err := arr.Scan(bytes) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", bytes, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr) - } - } -} - -func BenchmarkBoolArrayScanBytes(b *testing.B) { - var a BoolArray - var x interface{} = []byte(`{t,f,t,f,t,f,t,f,t,f}`) - - for i := 0; i < b.N; i++ { - a = BoolArray{} - a.Scan(x) - } -} - -func TestBoolArrayScanString(t *testing.T) { - for _, tt := range BoolArrayStringTests { - arr := BoolArray{true, true, true} - err := arr.Scan(tt.str) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", tt.str, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr) - } - } -} - -func TestBoolArrayScanError(t *testing.T) { - for _, tt := range []struct { - input, err string - }{ - {``, "unable to parse array"}, - {`{`, "unable to parse array"}, - {`{{t},{f}}`, "cannot convert ARRAY[2][1] to BoolArray"}, - {`{NULL}`, `could not parse boolean array index 0: invalid boolean ""`}, - {`{a}`, `could not parse boolean array index 0: invalid boolean "a"`}, - {`{t,b}`, `could not parse boolean array index 1: invalid boolean "b"`}, - {`{t,f,cd}`, `could not parse boolean array index 2: invalid boolean "cd"`}, - } { - arr := BoolArray{true, true, true} - err := arr.Scan(tt.input) - - if err == nil { - t.Fatalf("Expected error for %q, got none", tt.input) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err) - } - if !reflect.DeepEqual(arr, BoolArray{true, true, true}) { - t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr) - } - } -} - -func TestBoolArrayValue(t *testing.T) { - result, err := BoolArray(nil).Value() - - if err != nil { - t.Fatalf("Expected no error for nil, got %v", err) - } - if result != nil { - t.Errorf("Expected nil, got %q", result) - } - - result, err = BoolArray([]bool{}).Value() - - if err != nil { - t.Fatalf("Expected no error for empty, got %v", err) - } - if expected := `{}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected empty, got %q", result) - } - - result, err = BoolArray([]bool{false, true, false}).Value() - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if expected := `{f,t,f}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected %q, got %q", expected, result) - } -} - -func BenchmarkBoolArrayValue(b *testing.B) { - rand.Seed(1) - x := make([]bool, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.Intn(2) == 0 - } - a := BoolArray(x) - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func TestByteaArrayScanUnsupported(t *testing.T) { - var arr ByteaArray - err := arr.Scan(1) - - if err == nil { - t.Fatal("Expected error when scanning from int") - } - if !strings.Contains(err.Error(), "int to ByteaArray") { - t.Errorf("Expected type to be mentioned when scanning, got %q", err) - } -} - -func TestByteaArrayScanEmpty(t *testing.T) { - var arr ByteaArray - err := arr.Scan(`{}`) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr == nil || len(arr) != 0 { - t.Errorf("Expected empty, got %#v", arr) - } -} - -func TestByteaArrayScanNil(t *testing.T) { - arr := ByteaArray{{2}, {6}, {0, 0}} - err := arr.Scan(nil) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr != nil { - t.Errorf("Expected nil, got %+v", arr) - } -} - -var ByteaArrayStringTests = []struct { - str string - arr ByteaArray -}{ - {`{}`, ByteaArray{}}, - {`{NULL}`, ByteaArray{nil}}, - {`{"\\xfeff"}`, ByteaArray{{'\xFE', '\xFF'}}}, - {`{"\\xdead","\\xbeef"}`, ByteaArray{{'\xDE', '\xAD'}, {'\xBE', '\xEF'}}}, -} - -func TestByteaArrayScanBytes(t *testing.T) { - for _, tt := range ByteaArrayStringTests { - bytes := []byte(tt.str) - arr := ByteaArray{{2}, {6}, {0, 0}} - err := arr.Scan(bytes) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", bytes, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr) - } - } -} - -func BenchmarkByteaArrayScanBytes(b *testing.B) { - var a ByteaArray - var x interface{} = []byte(`{"\\xfe","\\xff","\\xdead","\\xbeef","\\xfe","\\xff","\\xdead","\\xbeef","\\xfe","\\xff"}`) - - for i := 0; i < b.N; i++ { - a = ByteaArray{} - a.Scan(x) - } -} - -func TestByteaArrayScanString(t *testing.T) { - for _, tt := range ByteaArrayStringTests { - arr := ByteaArray{{2}, {6}, {0, 0}} - err := arr.Scan(tt.str) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", tt.str, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr) - } - } -} - -func TestByteaArrayScanError(t *testing.T) { - for _, tt := range []struct { - input, err string - }{ - {``, "unable to parse array"}, - {`{`, "unable to parse array"}, - {`{{"\\xfeff"},{"\\xbeef"}}`, "cannot convert ARRAY[2][1] to ByteaArray"}, - {`{"\\abc"}`, "could not parse bytea array index 0: could not parse bytea value"}, - } { - arr := ByteaArray{{2}, {6}, {0, 0}} - err := arr.Scan(tt.input) - - if err == nil { - t.Fatalf("Expected error for %q, got none", tt.input) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err) - } - if !reflect.DeepEqual(arr, ByteaArray{{2}, {6}, {0, 0}}) { - t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr) - } - } -} - -func TestByteaArrayValue(t *testing.T) { - result, err := ByteaArray(nil).Value() - - if err != nil { - t.Fatalf("Expected no error for nil, got %v", err) - } - if result != nil { - t.Errorf("Expected nil, got %q", result) - } - - result, err = ByteaArray([][]byte{}).Value() - - if err != nil { - t.Fatalf("Expected no error for empty, got %v", err) - } - if expected := `{}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected empty, got %q", result) - } - - result, err = ByteaArray([][]byte{{'\xDE', '\xAD', '\xBE', '\xEF'}, {'\xFE', '\xFF'}, {}}).Value() - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if expected := `{"\\xdeadbeef","\\xfeff","\\x"}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected %q, got %q", expected, result) - } -} - -func BenchmarkByteaArrayValue(b *testing.B) { - rand.Seed(1) - x := make([][]byte, 10) - for i := 0; i < len(x); i++ { - x[i] = make([]byte, len(x)) - for j := 0; j < len(x); j++ { - x[i][j] = byte(rand.Int()) - } - } - a := ByteaArray(x) - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func TestFloat64ArrayScanUnsupported(t *testing.T) { - var arr Float64Array - err := arr.Scan(true) - - if err == nil { - t.Fatal("Expected error when scanning from bool") - } - if !strings.Contains(err.Error(), "bool to Float64Array") { - t.Errorf("Expected type to be mentioned when scanning, got %q", err) - } -} - -func TestFloat64ArrayScanEmpty(t *testing.T) { - var arr Float64Array - err := arr.Scan(`{}`) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr == nil || len(arr) != 0 { - t.Errorf("Expected empty, got %#v", arr) - } -} - -func TestFloat64ArrayScanNil(t *testing.T) { - arr := Float64Array{5, 5, 5} - err := arr.Scan(nil) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr != nil { - t.Errorf("Expected nil, got %+v", arr) - } -} - -var Float64ArrayStringTests = []struct { - str string - arr Float64Array -}{ - {`{}`, Float64Array{}}, - {`{1.2}`, Float64Array{1.2}}, - {`{3.456,7.89}`, Float64Array{3.456, 7.89}}, - {`{3,1,2}`, Float64Array{3, 1, 2}}, -} - -func TestFloat64ArrayScanBytes(t *testing.T) { - for _, tt := range Float64ArrayStringTests { - bytes := []byte(tt.str) - arr := Float64Array{5, 5, 5} - err := arr.Scan(bytes) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", bytes, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr) - } - } -} - -func BenchmarkFloat64ArrayScanBytes(b *testing.B) { - var a Float64Array - var x interface{} = []byte(`{1.2,3.4,5.6,7.8,9.01,2.34,5.67,8.90,1.234,5.678}`) - - for i := 0; i < b.N; i++ { - a = Float64Array{} - a.Scan(x) - } -} - -func TestFloat64ArrayScanString(t *testing.T) { - for _, tt := range Float64ArrayStringTests { - arr := Float64Array{5, 5, 5} - err := arr.Scan(tt.str) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", tt.str, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr) - } - } -} - -func TestFloat64ArrayScanError(t *testing.T) { - for _, tt := range []struct { - input, err string - }{ - {``, "unable to parse array"}, - {`{`, "unable to parse array"}, - {`{{5.6},{7.8}}`, "cannot convert ARRAY[2][1] to Float64Array"}, - {`{NULL}`, "parsing array element index 0:"}, - {`{a}`, "parsing array element index 0:"}, - {`{5.6,a}`, "parsing array element index 1:"}, - {`{5.6,7.8,a}`, "parsing array element index 2:"}, - } { - arr := Float64Array{5, 5, 5} - err := arr.Scan(tt.input) - - if err == nil { - t.Fatalf("Expected error for %q, got none", tt.input) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err) - } - if !reflect.DeepEqual(arr, Float64Array{5, 5, 5}) { - t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr) - } - } -} - -func TestFloat64ArrayValue(t *testing.T) { - result, err := Float64Array(nil).Value() - - if err != nil { - t.Fatalf("Expected no error for nil, got %v", err) - } - if result != nil { - t.Errorf("Expected nil, got %q", result) - } - - result, err = Float64Array([]float64{}).Value() - - if err != nil { - t.Fatalf("Expected no error for empty, got %v", err) - } - if expected := `{}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected empty, got %q", result) - } - - result, err = Float64Array([]float64{1.2, 3.4, 5.6}).Value() - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if expected := `{1.2,3.4,5.6}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected %q, got %q", expected, result) - } -} - -func BenchmarkFloat64ArrayValue(b *testing.B) { - rand.Seed(1) - x := make([]float64, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.NormFloat64() - } - a := Float64Array(x) - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func TestInt64ArrayScanUnsupported(t *testing.T) { - var arr Int64Array - err := arr.Scan(true) - - if err == nil { - t.Fatal("Expected error when scanning from bool") - } - if !strings.Contains(err.Error(), "bool to Int64Array") { - t.Errorf("Expected type to be mentioned when scanning, got %q", err) - } -} - -func TestInt64ArrayScanEmpty(t *testing.T) { - var arr Int64Array - err := arr.Scan(`{}`) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr == nil || len(arr) != 0 { - t.Errorf("Expected empty, got %#v", arr) - } -} - -func TestInt64ArrayScanNil(t *testing.T) { - arr := Int64Array{5, 5, 5} - err := arr.Scan(nil) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr != nil { - t.Errorf("Expected nil, got %+v", arr) - } -} - -var Int64ArrayStringTests = []struct { - str string - arr Int64Array -}{ - {`{}`, Int64Array{}}, - {`{12}`, Int64Array{12}}, - {`{345,678}`, Int64Array{345, 678}}, -} - -func TestInt64ArrayScanBytes(t *testing.T) { - for _, tt := range Int64ArrayStringTests { - bytes := []byte(tt.str) - arr := Int64Array{5, 5, 5} - err := arr.Scan(bytes) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", bytes, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr) - } - } -} - -func BenchmarkInt64ArrayScanBytes(b *testing.B) { - var a Int64Array - var x interface{} = []byte(`{1,2,3,4,5,6,7,8,9,0}`) - - for i := 0; i < b.N; i++ { - a = Int64Array{} - a.Scan(x) - } -} - -func TestInt64ArrayScanString(t *testing.T) { - for _, tt := range Int64ArrayStringTests { - arr := Int64Array{5, 5, 5} - err := arr.Scan(tt.str) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", tt.str, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr) - } - } -} - -func TestInt64ArrayScanError(t *testing.T) { - for _, tt := range []struct { - input, err string - }{ - {``, "unable to parse array"}, - {`{`, "unable to parse array"}, - {`{{5},{6}}`, "cannot convert ARRAY[2][1] to Int64Array"}, - {`{NULL}`, "parsing array element index 0:"}, - {`{a}`, "parsing array element index 0:"}, - {`{5,a}`, "parsing array element index 1:"}, - {`{5,6,a}`, "parsing array element index 2:"}, - } { - arr := Int64Array{5, 5, 5} - err := arr.Scan(tt.input) - - if err == nil { - t.Fatalf("Expected error for %q, got none", tt.input) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err) - } - if !reflect.DeepEqual(arr, Int64Array{5, 5, 5}) { - t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr) - } - } -} - -func TestInt64ArrayValue(t *testing.T) { - result, err := Int64Array(nil).Value() - - if err != nil { - t.Fatalf("Expected no error for nil, got %v", err) - } - if result != nil { - t.Errorf("Expected nil, got %q", result) - } - - result, err = Int64Array([]int64{}).Value() - - if err != nil { - t.Fatalf("Expected no error for empty, got %v", err) - } - if expected := `{}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected empty, got %q", result) - } - - result, err = Int64Array([]int64{1, 2, 3}).Value() - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if expected := `{1,2,3}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected %q, got %q", expected, result) - } -} - -func BenchmarkInt64ArrayValue(b *testing.B) { - rand.Seed(1) - x := make([]int64, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.Int63() - } - a := Int64Array(x) - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func TestFloat32ArrayScanUnsupported(t *testing.T) { - var arr Float32Array - err := arr.Scan(true) - - if err == nil { - t.Fatal("Expected error when scanning from bool") - } - if !strings.Contains(err.Error(), "bool to Float32Array") { - t.Errorf("Expected type to be mentioned when scanning, got %q", err) - } -} - -func TestFloat32ArrayScanEmpty(t *testing.T) { - var arr Float32Array - err := arr.Scan(`{}`) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr == nil || len(arr) != 0 { - t.Errorf("Expected empty, got %#v", arr) - } -} - -func TestFloat32ArrayScanNil(t *testing.T) { - arr := Float32Array{5, 5, 5} - err := arr.Scan(nil) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr != nil { - t.Errorf("Expected nil, got %+v", arr) - } -} - -var Float32ArrayStringTests = []struct { - str string - arr Float32Array -}{ - {`{}`, Float32Array{}}, - {`{1.2}`, Float32Array{1.2}}, - {`{3.456,7.89}`, Float32Array{3.456, 7.89}}, - {`{3,1,2}`, Float32Array{3, 1, 2}}, -} - -func TestFloat32ArrayScanBytes(t *testing.T) { - for _, tt := range Float32ArrayStringTests { - bytes := []byte(tt.str) - arr := Float32Array{5, 5, 5} - err := arr.Scan(bytes) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", bytes, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr) - } - } -} - -func BenchmarkFloat32ArrayScanBytes(b *testing.B) { - var a Float32Array - var x interface{} = []byte(`{1.2,3.4,5.6,7.8,9.01,2.34,5.67,8.90,1.234,5.678}`) - - for i := 0; i < b.N; i++ { - a = Float32Array{} - a.Scan(x) - } -} - -func TestFloat32ArrayScanString(t *testing.T) { - for _, tt := range Float32ArrayStringTests { - arr := Float32Array{5, 5, 5} - err := arr.Scan(tt.str) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", tt.str, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr) - } - } -} - -func TestFloat32ArrayScanError(t *testing.T) { - for _, tt := range []struct { - input, err string - }{ - {``, "unable to parse array"}, - {`{`, "unable to parse array"}, - {`{{5.6},{7.8}}`, "cannot convert ARRAY[2][1] to Float32Array"}, - {`{NULL}`, "parsing array element index 0:"}, - {`{a}`, "parsing array element index 0:"}, - {`{5.6,a}`, "parsing array element index 1:"}, - {`{5.6,7.8,a}`, "parsing array element index 2:"}, - } { - arr := Float32Array{5, 5, 5} - err := arr.Scan(tt.input) - - if err == nil { - t.Fatalf("Expected error for %q, got none", tt.input) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err) - } - if !reflect.DeepEqual(arr, Float32Array{5, 5, 5}) { - t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr) - } - } -} - -func TestFloat32ArrayValue(t *testing.T) { - result, err := Float32Array(nil).Value() - - if err != nil { - t.Fatalf("Expected no error for nil, got %v", err) - } - if result != nil { - t.Errorf("Expected nil, got %q", result) - } - - result, err = Float32Array([]float32{}).Value() - - if err != nil { - t.Fatalf("Expected no error for empty, got %v", err) - } - if expected := `{}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected empty, got %q", result) - } - - result, err = Float32Array([]float32{1.2, 3.4, 5.6}).Value() - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if expected := `{1.2,3.4,5.6}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected %q, got %q", expected, result) - } -} - -func BenchmarkFloat32ArrayValue(b *testing.B) { - rand.Seed(1) - x := make([]float32, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.Float32() - } - a := Float32Array(x) - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func TestInt32ArrayScanUnsupported(t *testing.T) { - var arr Int32Array - err := arr.Scan(true) - - if err == nil { - t.Fatal("Expected error when scanning from bool") - } - if !strings.Contains(err.Error(), "bool to Int32Array") { - t.Errorf("Expected type to be mentioned when scanning, got %q", err) - } -} - -func TestInt32ArrayScanEmpty(t *testing.T) { - var arr Int32Array - err := arr.Scan(`{}`) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr == nil || len(arr) != 0 { - t.Errorf("Expected empty, got %#v", arr) - } -} - -func TestInt32ArrayScanNil(t *testing.T) { - arr := Int32Array{5, 5, 5} - err := arr.Scan(nil) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr != nil { - t.Errorf("Expected nil, got %+v", arr) - } -} - -var Int32ArrayStringTests = []struct { - str string - arr Int32Array -}{ - {`{}`, Int32Array{}}, - {`{12}`, Int32Array{12}}, - {`{345,678}`, Int32Array{345, 678}}, -} - -func TestInt32ArrayScanBytes(t *testing.T) { - for _, tt := range Int32ArrayStringTests { - bytes := []byte(tt.str) - arr := Int32Array{5, 5, 5} - err := arr.Scan(bytes) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", bytes, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr) - } - } -} - -func BenchmarkInt32ArrayScanBytes(b *testing.B) { - var a Int32Array - var x interface{} = []byte(`{1,2,3,4,5,6,7,8,9,0}`) - - for i := 0; i < b.N; i++ { - a = Int32Array{} - a.Scan(x) - } -} - -func TestInt32ArrayScanString(t *testing.T) { - for _, tt := range Int32ArrayStringTests { - arr := Int32Array{5, 5, 5} - err := arr.Scan(tt.str) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", tt.str, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr) - } - } -} - -func TestInt32ArrayScanError(t *testing.T) { - for _, tt := range []struct { - input, err string - }{ - {``, "unable to parse array"}, - {`{`, "unable to parse array"}, - {`{{5},{6}}`, "cannot convert ARRAY[2][1] to Int32Array"}, - {`{NULL}`, "parsing array element index 0:"}, - {`{a}`, "parsing array element index 0:"}, - {`{5,a}`, "parsing array element index 1:"}, - {`{5,6,a}`, "parsing array element index 2:"}, - } { - arr := Int32Array{5, 5, 5} - err := arr.Scan(tt.input) - - if err == nil { - t.Fatalf("Expected error for %q, got none", tt.input) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err) - } - if !reflect.DeepEqual(arr, Int32Array{5, 5, 5}) { - t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr) - } - } -} - -func TestInt32ArrayValue(t *testing.T) { - result, err := Int32Array(nil).Value() - - if err != nil { - t.Fatalf("Expected no error for nil, got %v", err) - } - if result != nil { - t.Errorf("Expected nil, got %q", result) - } - - result, err = Int32Array([]int32{}).Value() - - if err != nil { - t.Fatalf("Expected no error for empty, got %v", err) - } - if expected := `{}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected empty, got %q", result) - } - - result, err = Int32Array([]int32{1, 2, 3}).Value() - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if expected := `{1,2,3}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected %q, got %q", expected, result) - } -} - -func BenchmarkInt32ArrayValue(b *testing.B) { - rand.Seed(1) - x := make([]int32, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.Int31() - } - a := Int32Array(x) - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func TestStringArrayScanUnsupported(t *testing.T) { - var arr StringArray - err := arr.Scan(true) - - if err == nil { - t.Fatal("Expected error when scanning from bool") - } - if !strings.Contains(err.Error(), "bool to StringArray") { - t.Errorf("Expected type to be mentioned when scanning, got %q", err) - } -} - -func TestStringArrayScanEmpty(t *testing.T) { - var arr StringArray - err := arr.Scan(`{}`) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr == nil || len(arr) != 0 { - t.Errorf("Expected empty, got %#v", arr) - } -} - -func TestStringArrayScanNil(t *testing.T) { - arr := StringArray{"x", "x", "x"} - err := arr.Scan(nil) - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if arr != nil { - t.Errorf("Expected nil, got %+v", arr) - } -} - -var StringArrayStringTests = []struct { - str string - arr StringArray -}{ - {`{}`, StringArray{}}, - {`{t}`, StringArray{"t"}}, - {`{f,1}`, StringArray{"f", "1"}}, - {`{"a\\b","c d",","}`, StringArray{"a\\b", "c d", ","}}, -} - -func TestStringArrayScanBytes(t *testing.T) { - for _, tt := range StringArrayStringTests { - bytes := []byte(tt.str) - arr := StringArray{"x", "x", "x"} - err := arr.Scan(bytes) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", bytes, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, bytes, arr) - } - } -} - -func BenchmarkStringArrayScanBytes(b *testing.B) { - var a StringArray - var x interface{} = []byte(`{a,b,c,d,e,f,g,h,i,j}`) - var y interface{} = []byte(`{"\a","\b","\c","\d","\e","\f","\g","\h","\i","\j"}`) - - for i := 0; i < b.N; i++ { - a = StringArray{} - a.Scan(x) - a = StringArray{} - a.Scan(y) - } -} - -func TestStringArrayScanString(t *testing.T) { - for _, tt := range StringArrayStringTests { - arr := StringArray{"x", "x", "x"} - err := arr.Scan(tt.str) - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", tt.str, err) - } - if !reflect.DeepEqual(arr, tt.arr) { - t.Errorf("Expected %+v for %q, got %+v", tt.arr, tt.str, arr) - } - } -} - -func TestStringArrayScanError(t *testing.T) { - for _, tt := range []struct { - input, err string - }{ - {``, "unable to parse array"}, - {`{`, "unable to parse array"}, - {`{{a},{b}}`, "cannot convert ARRAY[2][1] to StringArray"}, - {`{NULL}`, "parsing array element index 0: cannot convert nil to string"}, - {`{a,NULL}`, "parsing array element index 1: cannot convert nil to string"}, - {`{a,b,NULL}`, "parsing array element index 2: cannot convert nil to string"}, - } { - arr := StringArray{"x", "x", "x"} - err := arr.Scan(tt.input) - - if err == nil { - t.Fatalf("Expected error for %q, got none", tt.input) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for %q, got %q", tt.err, tt.input, err) - } - if !reflect.DeepEqual(arr, StringArray{"x", "x", "x"}) { - t.Errorf("Expected destination not to change for %q, got %+v", tt.input, arr) - } - } -} - -func TestStringArrayValue(t *testing.T) { - result, err := StringArray(nil).Value() - - if err != nil { - t.Fatalf("Expected no error for nil, got %v", err) - } - if result != nil { - t.Errorf("Expected nil, got %q", result) - } - - result, err = StringArray([]string{}).Value() - - if err != nil { - t.Fatalf("Expected no error for empty, got %v", err) - } - if expected := `{}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected empty, got %q", result) - } - - result, err = StringArray([]string{`a`, `\b`, `c"`, `d,e`}).Value() - - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if expected := `{"a","\\b","c\"","d,e"}`; !reflect.DeepEqual(result, expected) { - t.Errorf("Expected %q, got %q", expected, result) - } -} - -func BenchmarkStringArrayValue(b *testing.B) { - x := make([]string, 10) - for i := 0; i < len(x); i++ { - x[i] = strings.Repeat(`abc"def\ghi`, 5) - } - a := StringArray(x) - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func TestGenericArrayScanUnsupported(t *testing.T) { - var s string - var ss []string - var nsa [1]sql.NullString - - for _, tt := range []struct { - src, dest interface{} - err string - }{ - {nil, nil, "destination is not a pointer to array or slice"}, - {nil, true, "destination bool is not a pointer to array or slice"}, - {nil, &s, "destination *string is not a pointer to array or slice"}, - {nil, ss, "destination []string is not a pointer to array or slice"}, - {nil, &nsa, " to [1]sql.NullString"}, - {true, &ss, "bool to []string"}, - {`{{x}}`, &ss, "multidimensional ARRAY[1][1] is not implemented"}, - {`{{x},{x}}`, &ss, "multidimensional ARRAY[2][1] is not implemented"}, - {`{x}`, &ss, "scanning to string is not implemented"}, - } { - err := GenericArray{tt.dest}.Scan(tt.src) - - if err == nil { - t.Fatalf("Expected error for [%#v %#v]", tt.src, tt.dest) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for [%#v %#v], got %q", tt.err, tt.src, tt.dest, err) - } - } -} - -func TestGenericArrayScanScannerArrayBytes(t *testing.T) { - src, expected, nsa := []byte(`{NULL,abc,"\""}`), - [3]sql.NullString{{}, {String: `abc`, Valid: true}, {String: `"`, Valid: true}}, - [3]sql.NullString{{String: ``, Valid: true}, {}, {}} - - if err := (GenericArray{&nsa}).Scan(src); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if !reflect.DeepEqual(nsa, expected) { - t.Errorf("Expected %v, got %v", expected, nsa) - } -} - -func TestGenericArrayScanScannerArrayString(t *testing.T) { - src, expected, nsa := `{NULL,"\"",xyz}`, - [3]sql.NullString{{}, {String: `"`, Valid: true}, {String: `xyz`, Valid: true}}, - [3]sql.NullString{{String: ``, Valid: true}, {}, {}} - - if err := (GenericArray{&nsa}).Scan(src); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if !reflect.DeepEqual(nsa, expected) { - t.Errorf("Expected %v, got %v", expected, nsa) - } -} - -func TestGenericArrayScanScannerSliceEmpty(t *testing.T) { - var nss []sql.NullString - - if err := (GenericArray{&nss}).Scan(`{}`); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if nss == nil || len(nss) != 0 { - t.Errorf("Expected empty, got %#v", nss) - } -} - -func TestGenericArrayScanScannerSliceNil(t *testing.T) { - nss := []sql.NullString{{String: ``, Valid: true}, {}} - - if err := (GenericArray{&nss}).Scan(nil); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if nss != nil { - t.Errorf("Expected nil, got %+v", nss) - } -} - -func TestGenericArrayScanScannerSliceBytes(t *testing.T) { - src, expected, nss := []byte(`{NULL,abc,"\""}`), - []sql.NullString{{}, {String: `abc`, Valid: true}, {String: `"`, Valid: true}}, - []sql.NullString{{String: ``, Valid: true}, {}, {}, {}, {}} - - if err := (GenericArray{&nss}).Scan(src); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if !reflect.DeepEqual(nss, expected) { - t.Errorf("Expected %v, got %v", expected, nss) - } -} - -func BenchmarkGenericArrayScanScannerSliceBytes(b *testing.B) { - var a GenericArray - var x interface{} = []byte(`{a,b,c,d,e,f,g,h,i,j}`) - var y interface{} = []byte(`{"\a","\b","\c","\d","\e","\f","\g","\h","\i","\j"}`) - - for i := 0; i < b.N; i++ { - a = GenericArray{new([]sql.NullString)} - a.Scan(x) - a = GenericArray{new([]sql.NullString)} - a.Scan(y) - } -} - -func TestGenericArrayScanScannerSliceString(t *testing.T) { - src, expected, nss := `{NULL,"\"",xyz}`, - []sql.NullString{{}, {String: `"`, Valid: true}, {String: `xyz`, Valid: true}}, - []sql.NullString{{String: ``, Valid: true}, {}, {}} - - if err := (GenericArray{&nss}).Scan(src); err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if !reflect.DeepEqual(nss, expected) { - t.Errorf("Expected %v, got %v", expected, nss) - } -} - -type TildeNullInt64 struct{ sql.NullInt64 } - -func (TildeNullInt64) ArrayDelimiter() string { return "~" } - -func TestGenericArrayScanDelimiter(t *testing.T) { - src, expected, tnis := `{12~NULL~76}`, - []TildeNullInt64{{sql.NullInt64{Int64: 12, Valid: true}}, {}, {sql.NullInt64{Int64: 76, Valid: true}}}, - []TildeNullInt64{{sql.NullInt64{Int64: 0, Valid: true}}, {}} - - if err := (GenericArray{&tnis}).Scan(src); err != nil { - t.Fatalf("Expected no error for %#v, got %v", src, err) - } - if !reflect.DeepEqual(tnis, expected) { - t.Errorf("Expected %v for %#v, got %v", expected, src, tnis) - } -} - -func TestGenericArrayScanErrors(t *testing.T) { - var sa [1]string - var nis []sql.NullInt64 - var pss *[]string - - for _, tt := range []struct { - src, dest interface{} - err string - }{ - {nil, pss, "destination *[]string is nil"}, - {`{`, &sa, "unable to parse"}, - {`{}`, &sa, "cannot convert ARRAY[0] to [1]string"}, - {`{x,x}`, &sa, "cannot convert ARRAY[2] to [1]string"}, - {`{x}`, &nis, `parsing array element index 0: converting`}, - } { - err := GenericArray{tt.dest}.Scan(tt.src) - - if err == nil { - t.Fatalf("Expected error for [%#v %#v]", tt.src, tt.dest) - } - if !strings.Contains(err.Error(), tt.err) { - t.Errorf("Expected error to contain %q for [%#v %#v], got %q", tt.err, tt.src, tt.dest, err) - } - } -} - -func TestGenericArrayValueUnsupported(t *testing.T) { - _, err := GenericArray{true}.Value() - - if err == nil { - t.Fatal("Expected error for bool") - } - if !strings.Contains(err.Error(), "bool to array") { - t.Errorf("Expected type to be mentioned, got %q", err) - } -} - -type ByteArrayValuer [1]byte -type ByteSliceValuer []byte -type FuncArrayValuer struct { - delimiter func() string - value func() (driver.Value, error) -} - -func (a ByteArrayValuer) Value() (driver.Value, error) { return a[:], nil } -func (b ByteSliceValuer) Value() (driver.Value, error) { return []byte(b), nil } -func (f FuncArrayValuer) ArrayDelimiter() string { return f.delimiter() } -func (f FuncArrayValuer) Value() (driver.Value, error) { return f.value() } - -func TestGenericArrayValue(t *testing.T) { - result, err := GenericArray{nil}.Value() - - if err != nil { - t.Fatalf("Expected no error for nil, got %v", err) - } - if result != nil { - t.Errorf("Expected nil, got %q", result) - } - - for _, tt := range []interface{}{ - []bool(nil), - [][]int(nil), - []*int(nil), - []sql.NullString(nil), - } { - result, err := GenericArray{tt}.Value() - - if err != nil { - t.Fatalf("Expected no error for %#v, got %v", tt, err) - } - if result != nil { - t.Errorf("Expected nil for %#v, got %q", tt, result) - } - } - - Tilde := func(v driver.Value) FuncArrayValuer { - return FuncArrayValuer{ - func() string { return "~" }, - func() (driver.Value, error) { return v, nil }} - } - - for _, tt := range []struct { - result string - input interface{} - }{ - {`{}`, []bool{}}, - {`{true}`, []bool{true}}, - {`{true,false}`, []bool{true, false}}, - {`{true,false}`, [2]bool{true, false}}, - - {`{}`, [][]int{{}}}, - {`{}`, [][]int{{}, {}}}, - {`{{1}}`, [][]int{{1}}}, - {`{{1},{2}}`, [][]int{{1}, {2}}}, - {`{{1,2},{3,4}}`, [][]int{{1, 2}, {3, 4}}}, - {`{{1,2},{3,4}}`, [2][2]int{{1, 2}, {3, 4}}}, - - {`{"a","\\b","c\"","d,e"}`, []string{`a`, `\b`, `c"`, `d,e`}}, - {`{"a","\\b","c\"","d,e"}`, [][]byte{{'a'}, {'\\', 'b'}, {'c', '"'}, {'d', ',', 'e'}}}, - - {`{NULL}`, []*int{nil}}, - {`{0,NULL}`, []*int{new(int), nil}}, - - {`{NULL}`, []sql.NullString{{}}}, - {`{"\"",NULL}`, []sql.NullString{{String: `"`, Valid: true}, {}}}, - - {`{"a","b"}`, []ByteArrayValuer{{'a'}, {'b'}}}, - {`{{"a","b"},{"c","d"}}`, [][]ByteArrayValuer{{{'a'}, {'b'}}, {{'c'}, {'d'}}}}, - - {`{"e","f"}`, []ByteSliceValuer{{'e'}, {'f'}}}, - {`{{"e","f"},{"g","h"}}`, [][]ByteSliceValuer{{{'e'}, {'f'}}, {{'g'}, {'h'}}}}, - - {`{1~2}`, []FuncArrayValuer{Tilde(int64(1)), Tilde(int64(2))}}, - {`{{1~2}~{3~4}}`, [][]FuncArrayValuer{{Tilde(int64(1)), Tilde(int64(2))}, {Tilde(int64(3)), Tilde(int64(4))}}}, - } { - result, err := GenericArray{tt.input}.Value() - - if err != nil { - t.Fatalf("Expected no error for %q, got %v", tt.input, err) - } - if !reflect.DeepEqual(result, tt.result) { - t.Errorf("Expected %q for %q, got %q", tt.result, tt.input, result) - } - } -} - -func TestGenericArrayValueErrors(t *testing.T) { - v := []interface{}{func() {}} - if _, err := (GenericArray{v}).Value(); err == nil { - t.Errorf("Expected error for %q, got nil", v) - } - - v = []interface{}{nil, func() {}} - if _, err := (GenericArray{v}).Value(); err == nil { - t.Errorf("Expected error for %q, got nil", v) - } -} - -func BenchmarkGenericArrayValueBools(b *testing.B) { - rand.Seed(1) - x := make([]bool, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.Intn(2) == 0 - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func BenchmarkGenericArrayValueFloat64s(b *testing.B) { - rand.Seed(1) - x := make([]float64, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.NormFloat64() - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func BenchmarkGenericArrayValueInt64s(b *testing.B) { - rand.Seed(1) - x := make([]int64, 10) - for i := 0; i < len(x); i++ { - x[i] = rand.Int63() - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func BenchmarkGenericArrayValueByteSlices(b *testing.B) { - x := make([][]byte, 10) - for i := 0; i < len(x); i++ { - x[i] = bytes.Repeat([]byte(`abc"def\ghi`), 5) - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func BenchmarkGenericArrayValueStrings(b *testing.B) { - x := make([]string, 10) - for i := 0; i < len(x); i++ { - x[i] = strings.Repeat(`abc"def\ghi`, 5) - } - a := GenericArray{x} - - for i := 0; i < b.N; i++ { - a.Value() - } -} - -func TestArrayScanBackend(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - for _, tt := range []struct { - s string - d sql.Scanner - e interface{} - }{ - {`ARRAY[true, false]`, new(BoolArray), &BoolArray{true, false}}, - {`ARRAY[E'\\xdead', E'\\xbeef']`, new(ByteaArray), &ByteaArray{{'\xDE', '\xAD'}, {'\xBE', '\xEF'}}}, - {`ARRAY[1.2, 3.4]`, new(Float64Array), &Float64Array{1.2, 3.4}}, - {`ARRAY[1, 2, 3]`, new(Int64Array), &Int64Array{1, 2, 3}}, - {`ARRAY['a', E'\\b', 'c"', 'd,e']`, new(StringArray), &StringArray{`a`, `\b`, `c"`, `d,e`}}, - } { - err := db.QueryRow(`SELECT ` + tt.s).Scan(tt.d) - if err != nil { - t.Errorf("Expected no error when scanning %s into %T, got %v", tt.s, tt.d, err) - } - if !reflect.DeepEqual(tt.d, tt.e) { - t.Errorf("Expected %v when scanning %s into %T, got %v", tt.e, tt.s, tt.d, tt.d) - } - } -} - -func TestArrayValueBackend(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - for _, tt := range []struct { - s string - v driver.Valuer - }{ - {`ARRAY[true, false]`, BoolArray{true, false}}, - {`ARRAY[E'\\xdead', E'\\xbeef']`, ByteaArray{{'\xDE', '\xAD'}, {'\xBE', '\xEF'}}}, - {`ARRAY[1.2, 3.4]`, Float64Array{1.2, 3.4}}, - {`ARRAY[1, 2, 3]`, Int64Array{1, 2, 3}}, - {`ARRAY['a', E'\\b', 'c"', 'd,e']`, StringArray{`a`, `\b`, `c"`, `d,e`}}, - } { - var x int - err := db.QueryRow(`SELECT 1 WHERE `+tt.s+` <> $1`, tt.v).Scan(&x) - if err != sql.ErrNoRows { - t.Errorf("Expected %v to equal %s, got %v", tt.v, tt.s, err) - } - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/go.mod b/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/go.mod deleted file mode 100644 index d58d6df48..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/go.mod +++ /dev/null @@ -1,8 +0,0 @@ -module github.com/lib/pq/auth/kerberos - -go 1.13 - -require ( - github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 - github.com/jcmturner/gokrb5/v8 v8.2.0 -) diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/go.sum b/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/go.sum deleted file mode 100644 index 138e36f1d..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/go.sum +++ /dev/null @@ -1,40 +0,0 @@ -github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5 h1:P5U+E4x5OkVEKQDklVPmzs71WM56RTTRqV4OrDC//Y4= -github.com/alexbrainman/sspi v0.0.0-20180613141037-e580b900e9f5/go.mod h1:976q2ETgjT2snVCf2ZaBnyBbVoPERGjUz+0sofzEfro= -github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= -github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/gorilla/securecookie v1.1.1 h1:miw7JPhV+b/lAHSXz4qd/nN9jRiAFV5FwjeKyCS8BvQ= -github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= -github.com/gorilla/sessions v1.2.0 h1:S7P+1Hm5V/AT9cjEcUD5uDaQSX0OE577aCXgoaKpYbQ= -github.com/gorilla/sessions v1.2.0/go.mod h1:dk2InVEVJ0sfLlnXv9EAgkf6ecYs/i80K/zI+bUmuGM= -github.com/hashicorp/go-uuid v1.0.2 h1:cfejS+Tpcp13yd5nYHWDI6qVCny6wyX2Mt5SGur2IGE= -github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= -github.com/jcmturner/aescts/v2 v2.0.0 h1:9YKLH6ey7H4eDBXW8khjYslgyqG2xZikXP0EQFKrle8= -github.com/jcmturner/aescts/v2 v2.0.0/go.mod h1:AiaICIRyfYg35RUkr8yESTqvSy7csK90qZ5xfvvsoNs= -github.com/jcmturner/dnsutils/v2 v2.0.0 h1:lltnkeZGL0wILNvrNiVCR6Ro5PGU/SeBvVO/8c/iPbo= -github.com/jcmturner/dnsutils/v2 v2.0.0/go.mod h1:b0TnjGOvI/n42bZa+hmXL+kFJZsFT7G4t3HTlQ184QM= -github.com/jcmturner/gofork v1.0.0 h1:J7uCkflzTEhUZ64xqKnkDxq3kzc96ajM1Gli5ktUem8= -github.com/jcmturner/gofork v1.0.0/go.mod h1:MK8+TM0La+2rjBD4jE12Kj1pCCxK7d2LK/UM3ncEo0o= -github.com/jcmturner/goidentity/v6 v6.0.1 h1:VKnZd2oEIMorCTsFBnJWbExfNN7yZr3EhJAxwOkZg6o= -github.com/jcmturner/goidentity/v6 v6.0.1/go.mod h1:X1YW3bgtvwAXju7V3LCIMpY0Gbxyjn/mY9zx4tFonSg= -github.com/jcmturner/gokrb5/v8 v8.2.0 h1:lzPl/30ZLkTveYsYZPKMcgXc8MbnE6RsTd4F9KgiLtk= -github.com/jcmturner/gokrb5/v8 v8.2.0/go.mod h1:T1hnNppQsBtxW0tCHMHTkAt8n/sABdzZgZdoFrZaZNM= -github.com/jcmturner/rpc/v2 v2.0.2 h1:gMB4IwRXYsWw4Bc6o/az2HJgFUA1ffSh90i26ZJ6Xl0= -github.com/jcmturner/rpc/v2 v2.0.2/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= -github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= -github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= -github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= -golang.org/x/crypto v0.0.0-20200117160349-530e935923ad h1:Jh8cai0fqIK+f6nG0UgPW5wFk8wmiMhM3AyciDBdtQg= -golang.org/x/crypto v0.0.0-20200117160349-530e935923ad/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= -golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa h1:F+8P+gmewFQYRk6JoLQLwjBCTu3mcIURZfNkVweuRKA= -golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= -golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= -golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= -gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= -gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= -gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/krb.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/krb.go deleted file mode 100644 index 451a7ee1b..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/krb.go +++ /dev/null @@ -1,29 +0,0 @@ -package kerberos - -import ( - "net" - "strings" -) - -/* - * Find the A record associated with a hostname - * In general, hostnames supplied to the driver should be - * canonicalized because the KDC usually only has one - * principal and not one per potential alias of a host. - */ -func canonicalizeHostname(host string) (string, error) { - canon := host - - name, err := net.LookupCNAME(host) - if err != nil { - return "", err - } - - name = strings.TrimSuffix(name, ".") - - if name != "" { - canon = name - } - - return canon, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/krb_unix.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/krb_unix.go deleted file mode 100644 index b6f27ce57..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/krb_unix.go +++ /dev/null @@ -1,128 +0,0 @@ -//go:build !windows -// +build !windows - -package kerberos - -import ( - "fmt" - "os" - "os/user" - "strings" - - "github.com/jcmturner/gokrb5/v8/client" - "github.com/jcmturner/gokrb5/v8/config" - "github.com/jcmturner/gokrb5/v8/credentials" - "github.com/jcmturner/gokrb5/v8/spnego" -) - -/* - * UNIX Kerberos support, using jcmturner's pure-go - * implementation - */ - -// GSS implements the pq.GSS interface. -type GSS struct { - cli *client.Client -} - -// NewGSS creates a new GSS provider. -func NewGSS() (*GSS, error) { - g := &GSS{} - err := g.init() - - if err != nil { - return nil, err - } - - return g, nil -} - -func (g *GSS) init() error { - cfgPath, ok := os.LookupEnv("KRB5_CONFIG") - if !ok { - cfgPath = "/etc/krb5.conf" - } - - cfg, err := config.Load(cfgPath) - if err != nil { - return err - } - - u, err := user.Current() - if err != nil { - return err - } - - ccpath := "/tmp/krb5cc_" + u.Uid - - ccname := os.Getenv("KRB5CCNAME") - if strings.HasPrefix(ccname, "FILE:") { - ccpath = strings.SplitN(ccname, ":", 2)[1] - } - - ccache, err := credentials.LoadCCache(ccpath) - if err != nil { - return err - } - - cl, err := client.NewFromCCache(ccache, cfg, client.DisablePAFXFAST(true)) - if err != nil { - return err - } - - cl.Login() - - g.cli = cl - - return nil -} - -// GetInitToken implements the GSS interface. -func (g *GSS) GetInitToken(host string, service string) ([]byte, error) { - - // Resolve the hostname down to an 'A' record, if required (usually, it is) - if g.cli.Config.LibDefaults.DNSCanonicalizeHostname { - var err error - host, err = canonicalizeHostname(host) - if err != nil { - return nil, err - } - } - - spn := service + "/" + host - - return g.GetInitTokenFromSpn(spn) -} - -// GetInitTokenFromSpn implements the GSS interface. -func (g *GSS) GetInitTokenFromSpn(spn string) ([]byte, error) { - s := spnego.SPNEGOClient(g.cli, spn) - - st, err := s.InitSecContext() - if err != nil { - return nil, fmt.Errorf("kerberos error (InitSecContext): %s", err.Error()) - } - - b, err := st.Marshal() - if err != nil { - return nil, fmt.Errorf("kerberos error (Marshaling token): %s", err.Error()) - } - - return b, nil -} - -// Continue implements the GSS interface. -func (g *GSS) Continue(inToken []byte) (done bool, outToken []byte, err error) { - t := &spnego.SPNEGOToken{} - err = t.Unmarshal(inToken) - if err != nil { - return true, nil, fmt.Errorf("kerberos error (Unmarshaling token): %s", err.Error()) - } - - state := t.NegTokenResp.State() - if state != spnego.NegStateAcceptCompleted { - return true, nil, fmt.Errorf("kerberos: expected state 'Completed' - got %d", state) - } - - return true, nil, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/krb_windows.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/krb_windows.go deleted file mode 100644 index ca26d02c6..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/auth/kerberos/krb_windows.go +++ /dev/null @@ -1,67 +0,0 @@ -//go:build windows -// +build windows - -package kerberos - -import ( - "github.com/alexbrainman/sspi" - "github.com/alexbrainman/sspi/negotiate" -) - -// GSS implements the pq.GSS interface. -type GSS struct { - creds *sspi.Credentials - ctx *negotiate.ClientContext -} - -// NewGSS creates a new GSS provider. -func NewGSS() (*GSS, error) { - g := &GSS{} - err := g.init() - - if err != nil { - return nil, err - } - - return g, nil -} - -func (g *GSS) init() error { - creds, err := negotiate.AcquireCurrentUserCredentials() - if err != nil { - return err - } - - g.creds = creds - return nil -} - -// GetInitToken implements the GSS interface. -func (g *GSS) GetInitToken(host string, service string) ([]byte, error) { - - host, err := canonicalizeHostname(host) - if err != nil { - return nil, err - } - - spn := service + "/" + host - - return g.GetInitTokenFromSpn(spn) -} - -// GetInitTokenFromSpn implements the GSS interface. -func (g *GSS) GetInitTokenFromSpn(spn string) ([]byte, error) { - ctx, token, err := negotiate.NewClientContext(g.creds, spn) - if err != nil { - return nil, err - } - - g.ctx = ctx - - return token, nil -} - -// Continue implements the GSS interface. -func (g *GSS) Continue(inToken []byte) (done bool, outToken []byte, err error) { - return g.ctx.Update(inToken) -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/bench_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/bench_test.go deleted file mode 100644 index b3754980a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/bench_test.go +++ /dev/null @@ -1,434 +0,0 @@ -package pq - -import ( - "bufio" - "bytes" - "context" - "database/sql" - "database/sql/driver" - "io" - "math/rand" - "net" - "runtime" - "strconv" - "strings" - "sync" - "testing" - "time" - - "github.com/lib/pq/oid" -) - -var ( - selectStringQuery = "SELECT '" + strings.Repeat("0123456789", 10) + "'" - selectSeriesQuery = "SELECT generate_series(1, 100)" -) - -func BenchmarkSelectString(b *testing.B) { - var result string - benchQuery(b, selectStringQuery, &result) -} - -func BenchmarkSelectSeries(b *testing.B) { - var result int - benchQuery(b, selectSeriesQuery, &result) -} - -func benchQuery(b *testing.B, query string, result interface{}) { - b.StopTimer() - db := openTestConn(b) - defer db.Close() - b.StartTimer() - - for i := 0; i < b.N; i++ { - benchQueryLoop(b, db, query, result) - } -} - -func benchQueryLoop(b *testing.B, db *sql.DB, query string, result interface{}) { - rows, err := db.Query(query) - if err != nil { - b.Fatal(err) - } - defer rows.Close() - for rows.Next() { - err = rows.Scan(result) - if err != nil { - b.Fatal("failed to scan", err) - } - } -} - -// reading from circularConn yields content[:prefixLen] once, followed by -// content[prefixLen:] over and over again. It never returns EOF. -type circularConn struct { - content string - prefixLen int - pos int - net.Conn // for all other net.Conn methods that will never be called -} - -func (r *circularConn) Read(b []byte) (n int, err error) { - n = copy(b, r.content[r.pos:]) - r.pos += n - if r.pos >= len(r.content) { - r.pos = r.prefixLen - } - return -} - -func (r *circularConn) Write(b []byte) (n int, err error) { return len(b), nil } - -func (r *circularConn) Close() error { return nil } - -func fakeConn(content string, prefixLen int) *conn { - c := &circularConn{content: content, prefixLen: prefixLen} - return &conn{buf: bufio.NewReader(c), c: c} -} - -// This benchmark is meant to be the same as BenchmarkSelectString, but takes -// out some of the factors this package can't control. The numbers are less noisy, -// but also the costs of network communication aren't accurately represented. -func BenchmarkMockSelectString(b *testing.B) { - b.StopTimer() - // taken from a recorded run of BenchmarkSelectString - // See: http://www.postgresql.org/docs/current/static/protocol-message-formats.html - const response = "1\x00\x00\x00\x04" + - "t\x00\x00\x00\x06\x00\x00" + - "T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" + - "Z\x00\x00\x00\x05I" + - "2\x00\x00\x00\x04" + - "D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + - "C\x00\x00\x00\rSELECT 1\x00" + - "Z\x00\x00\x00\x05I" + - "3\x00\x00\x00\x04" + - "Z\x00\x00\x00\x05I" - c := fakeConn(response, 0) - b.StartTimer() - - for i := 0; i < b.N; i++ { - benchMockQuery(b, c, selectStringQuery) - } -} - -var seriesRowData = func() string { - var buf bytes.Buffer - for i := 1; i <= 100; i++ { - digits := byte(2) - if i >= 100 { - digits = 3 - } else if i < 10 { - digits = 1 - } - buf.WriteString("D\x00\x00\x00") - buf.WriteByte(10 + digits) - buf.WriteString("\x00\x01\x00\x00\x00") - buf.WriteByte(digits) - buf.WriteString(strconv.Itoa(i)) - } - return buf.String() -}() - -func BenchmarkMockSelectSeries(b *testing.B) { - b.StopTimer() - var response = "1\x00\x00\x00\x04" + - "t\x00\x00\x00\x06\x00\x00" + - "T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" + - "Z\x00\x00\x00\x05I" + - "2\x00\x00\x00\x04" + - seriesRowData + - "C\x00\x00\x00\x0fSELECT 100\x00" + - "Z\x00\x00\x00\x05I" + - "3\x00\x00\x00\x04" + - "Z\x00\x00\x00\x05I" - c := fakeConn(response, 0) - b.StartTimer() - - for i := 0; i < b.N; i++ { - benchMockQuery(b, c, selectSeriesQuery) - } -} - -func benchMockQuery(b *testing.B, c *conn, query string) { - stmt, err := c.Prepare(query) - if err != nil { - b.Fatal(err) - } - defer stmt.Close() - rows, err := stmt.(driver.StmtQueryContext).QueryContext(context.Background(), nil) - if err != nil { - b.Fatal(err) - } - defer rows.Close() - var dest [1]driver.Value - for { - if err := rows.Next(dest[:]); err != nil { - if err == io.EOF { - break - } - b.Fatal(err) - } - } -} - -func BenchmarkPreparedSelectString(b *testing.B) { - var result string - benchPreparedQuery(b, selectStringQuery, &result) -} - -func BenchmarkPreparedSelectSeries(b *testing.B) { - var result int - benchPreparedQuery(b, selectSeriesQuery, &result) -} - -func benchPreparedQuery(b *testing.B, query string, result interface{}) { - b.StopTimer() - db := openTestConn(b) - defer db.Close() - stmt, err := db.Prepare(query) - if err != nil { - b.Fatal(err) - } - defer stmt.Close() - b.StartTimer() - - for i := 0; i < b.N; i++ { - benchPreparedQueryLoop(b, db, stmt, result) - } -} - -func benchPreparedQueryLoop(b *testing.B, db *sql.DB, stmt *sql.Stmt, result interface{}) { - rows, err := stmt.Query() - if err != nil { - b.Fatal(err) - } - if !rows.Next() { - rows.Close() - b.Fatal("no rows") - } - defer rows.Close() - for rows.Next() { - err = rows.Scan(&result) - if err != nil { - b.Fatal("failed to scan") - } - } -} - -// See the comment for BenchmarkMockSelectString. -func BenchmarkMockPreparedSelectString(b *testing.B) { - b.StopTimer() - const parseResponse = "1\x00\x00\x00\x04" + - "t\x00\x00\x00\x06\x00\x00" + - "T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" + - "Z\x00\x00\x00\x05I" - const responses = parseResponse + - "2\x00\x00\x00\x04" + - "D\x00\x00\x00n\x00\x01\x00\x00\x00d0123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789" + - "C\x00\x00\x00\rSELECT 1\x00" + - "Z\x00\x00\x00\x05I" - c := fakeConn(responses, len(parseResponse)) - - stmt, err := c.Prepare(selectStringQuery) - if err != nil { - b.Fatal(err) - } - b.StartTimer() - - for i := 0; i < b.N; i++ { - benchPreparedMockQuery(b, c, stmt) - } -} - -func BenchmarkMockPreparedSelectSeries(b *testing.B) { - b.StopTimer() - const parseResponse = "1\x00\x00\x00\x04" + - "t\x00\x00\x00\x06\x00\x00" + - "T\x00\x00\x00!\x00\x01?column?\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02\xc1\xff\xfe\xff\xff\xff\xff\x00\x00" + - "Z\x00\x00\x00\x05I" - var responses = parseResponse + - "2\x00\x00\x00\x04" + - seriesRowData + - "C\x00\x00\x00\x0fSELECT 100\x00" + - "Z\x00\x00\x00\x05I" - c := fakeConn(responses, len(parseResponse)) - - stmt, err := c.Prepare(selectSeriesQuery) - if err != nil { - b.Fatal(err) - } - b.StartTimer() - - for i := 0; i < b.N; i++ { - benchPreparedMockQuery(b, c, stmt) - } -} - -func benchPreparedMockQuery(b *testing.B, c *conn, stmt driver.Stmt) { - rows, err := stmt.(driver.StmtQueryContext).QueryContext(context.Background(), nil) - if err != nil { - b.Fatal(err) - } - defer rows.Close() - var dest [1]driver.Value - for { - if err := rows.Next(dest[:]); err != nil { - if err == io.EOF { - break - } - b.Fatal(err) - } - } -} - -func BenchmarkEncodeInt64(b *testing.B) { - for i := 0; i < b.N; i++ { - encode(¶meterStatus{}, int64(1234), oid.T_int8) - } -} - -func BenchmarkEncodeFloat64(b *testing.B) { - for i := 0; i < b.N; i++ { - encode(¶meterStatus{}, 3.14159, oid.T_float8) - } -} - -var testByteString = []byte("abcdefghijklmnopqrstuvwxyz") - -func BenchmarkEncodeByteaHex(b *testing.B) { - for i := 0; i < b.N; i++ { - encode(¶meterStatus{serverVersion: 90000}, testByteString, oid.T_bytea) - } -} -func BenchmarkEncodeByteaEscape(b *testing.B) { - for i := 0; i < b.N; i++ { - encode(¶meterStatus{serverVersion: 84000}, testByteString, oid.T_bytea) - } -} - -func BenchmarkEncodeBool(b *testing.B) { - for i := 0; i < b.N; i++ { - encode(¶meterStatus{}, true, oid.T_bool) - } -} - -var testTimestamptz = time.Date(2001, time.January, 1, 0, 0, 0, 0, time.Local) - -func BenchmarkEncodeTimestamptz(b *testing.B) { - for i := 0; i < b.N; i++ { - encode(¶meterStatus{}, testTimestamptz, oid.T_timestamptz) - } -} - -var testIntBytes = []byte("1234") - -func BenchmarkDecodeInt64(b *testing.B) { - for i := 0; i < b.N; i++ { - decode(¶meterStatus{}, testIntBytes, oid.T_int8, formatText) - } -} - -var testFloatBytes = []byte("3.14159") - -func BenchmarkDecodeFloat64(b *testing.B) { - for i := 0; i < b.N; i++ { - decode(¶meterStatus{}, testFloatBytes, oid.T_float8, formatText) - } -} - -var testBoolBytes = []byte{'t'} - -func BenchmarkDecodeBool(b *testing.B) { - for i := 0; i < b.N; i++ { - decode(¶meterStatus{}, testBoolBytes, oid.T_bool, formatText) - } -} - -func TestDecodeBool(t *testing.T) { - db := openTestConn(t) - rows, err := db.Query("select true") - if err != nil { - t.Fatal(err) - } - rows.Close() -} - -var testTimestamptzBytes = []byte("2013-09-17 22:15:32.360754-07") - -func BenchmarkDecodeTimestamptz(b *testing.B) { - for i := 0; i < b.N; i++ { - decode(¶meterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText) - } -} - -func BenchmarkDecodeTimestamptzMultiThread(b *testing.B) { - oldProcs := runtime.GOMAXPROCS(0) - defer runtime.GOMAXPROCS(oldProcs) - runtime.GOMAXPROCS(runtime.NumCPU()) - globalLocationCache = newLocationCache() - - f := func(wg *sync.WaitGroup, loops int) { - defer wg.Done() - for i := 0; i < loops; i++ { - decode(¶meterStatus{}, testTimestamptzBytes, oid.T_timestamptz, formatText) - } - } - - wg := &sync.WaitGroup{} - b.ResetTimer() - for j := 0; j < 10; j++ { - wg.Add(1) - go f(wg, b.N/10) - } - wg.Wait() -} - -func BenchmarkLocationCache(b *testing.B) { - globalLocationCache = newLocationCache() - for i := 0; i < b.N; i++ { - globalLocationCache.getLocation(rand.Intn(10000)) - } -} - -func BenchmarkLocationCacheMultiThread(b *testing.B) { - oldProcs := runtime.GOMAXPROCS(0) - defer runtime.GOMAXPROCS(oldProcs) - runtime.GOMAXPROCS(runtime.NumCPU()) - globalLocationCache = newLocationCache() - - f := func(wg *sync.WaitGroup, loops int) { - defer wg.Done() - for i := 0; i < loops; i++ { - globalLocationCache.getLocation(rand.Intn(10000)) - } - } - - wg := &sync.WaitGroup{} - b.ResetTimer() - for j := 0; j < 10; j++ { - wg.Add(1) - go f(wg, b.N/10) - } - wg.Wait() -} - -// Stress test the performance of parsing results from the wire. -func BenchmarkResultParsing(b *testing.B) { - b.StopTimer() - - db := openTestConn(b) - defer db.Close() - _, err := db.Exec("BEGIN") - if err != nil { - b.Fatal(err) - } - - b.StartTimer() - for i := 0; i < b.N; i++ { - res, err := db.Query("SELECT generate_series(1, 50000)") - if err != nil { - b.Fatal(err) - } - res.Close() - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/buf.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/buf.go deleted file mode 100644 index 4b0a0a8f7..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/buf.go +++ /dev/null @@ -1,91 +0,0 @@ -package pq - -import ( - "bytes" - "encoding/binary" - - "github.com/lib/pq/oid" -) - -type readBuf []byte - -func (b *readBuf) int32() (n int) { - n = int(int32(binary.BigEndian.Uint32(*b))) - *b = (*b)[4:] - return -} - -func (b *readBuf) oid() (n oid.Oid) { - n = oid.Oid(binary.BigEndian.Uint32(*b)) - *b = (*b)[4:] - return -} - -// N.B: this is actually an unsigned 16-bit integer, unlike int32 -func (b *readBuf) int16() (n int) { - n = int(binary.BigEndian.Uint16(*b)) - *b = (*b)[2:] - return -} - -func (b *readBuf) string() string { - i := bytes.IndexByte(*b, 0) - if i < 0 { - errorf("invalid message format; expected string terminator") - } - s := (*b)[:i] - *b = (*b)[i+1:] - return string(s) -} - -func (b *readBuf) next(n int) (v []byte) { - v = (*b)[:n] - *b = (*b)[n:] - return -} - -func (b *readBuf) byte() byte { - return b.next(1)[0] -} - -type writeBuf struct { - buf []byte - pos int -} - -func (b *writeBuf) int32(n int) { - x := make([]byte, 4) - binary.BigEndian.PutUint32(x, uint32(n)) - b.buf = append(b.buf, x...) -} - -func (b *writeBuf) int16(n int) { - x := make([]byte, 2) - binary.BigEndian.PutUint16(x, uint16(n)) - b.buf = append(b.buf, x...) -} - -func (b *writeBuf) string(s string) { - b.buf = append(append(b.buf, s...), '\000') -} - -func (b *writeBuf) byte(c byte) { - b.buf = append(b.buf, c) -} - -func (b *writeBuf) bytes(v []byte) { - b.buf = append(b.buf, v...) -} - -func (b *writeBuf) wrap() []byte { - p := b.buf[b.pos:] - binary.BigEndian.PutUint32(p, uint32(len(p))) - return b.buf -} - -func (b *writeBuf) next(c byte) { - p := b.buf[b.pos:] - binary.BigEndian.PutUint32(p, uint32(len(p))) - b.pos = len(b.buf) + 1 - b.buf = append(b.buf, c, 0, 0, 0, 0) -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/buf_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/buf_test.go deleted file mode 100644 index df88d38b4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/buf_test.go +++ /dev/null @@ -1,16 +0,0 @@ -package pq - -import "testing" - -func Benchmark_writeBuf_string(b *testing.B) { - var buf writeBuf - const s = "foo" - - b.ReportAllocs() - b.ResetTimer() - - for i := 0; i < b.N; i++ { - buf.string(s) - buf.buf = buf.buf[:0] - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/Makefile b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/Makefile deleted file mode 100644 index a84e31e9c..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/Makefile +++ /dev/null @@ -1,37 +0,0 @@ -.PHONY: all root-ssl server-ssl client-ssl - -# Rebuilds self-signed root/server/client certs/keys in a consistent way -all: root-ssl server-ssl client-ssl - rm -f .srl - -root-ssl: - openssl req -new -sha256 -nodes -newkey rsa:2048 \ - -config ./certs/root.cnf \ - -keyout /tmp/root.key \ - -out /tmp/root.csr - openssl x509 -req -days 3653 -sha256 \ - -in /tmp/root.csr \ - -extfile /etc/ssl/openssl.cnf -extensions v3_ca \ - -signkey /tmp/root.key \ - -out ./certs/root.crt - -server-ssl: - openssl req -new -sha256 -nodes -newkey rsa:2048 \ - -config ./certs/server.cnf \ - -keyout ./certs/server.key \ - -out /tmp/server.csr - openssl x509 -req -days 3653 -sha256 \ - -extfile ./certs/server.cnf -extensions req_ext \ - -CA ./certs/root.crt -CAkey /tmp/root.key -CAcreateserial \ - -in /tmp/server.csr \ - -out ./certs/server.crt - -client-ssl: - openssl req -new -sha256 -nodes -newkey rsa:2048 \ - -config ./certs/postgresql.cnf \ - -keyout ./certs/postgresql.key \ - -out /tmp/postgresql.csr - openssl x509 -req -days 3653 -sha256 \ - -CA ./certs/root.crt -CAkey /tmp/root.key -CAcreateserial \ - -in /tmp/postgresql.csr \ - -out ./certs/postgresql.crt diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/README b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/README deleted file mode 100644 index 24ab7b256..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/README +++ /dev/null @@ -1,3 +0,0 @@ -This directory contains certificates and private keys for testing some -SSL-related functionality in Travis. Do NOT use these certificates for -anything other than testing. diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/bogus_root.crt b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/bogus_root.crt deleted file mode 100644 index 1239db3a4..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/bogus_root.crt +++ /dev/null @@ -1,19 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDBjCCAe6gAwIBAgIQSnDYp/Naet9HOZljF5PuwDANBgkqhkiG9w0BAQsFADAr -MRIwEAYDVQQKEwlDb2Nrcm9hY2gxFTATBgNVBAMTDENvY2tyb2FjaCBDQTAeFw0x -NjAyMDcxNjQ0MzdaFw0xNzAyMDYxNjQ0MzdaMCsxEjAQBgNVBAoTCUNvY2tyb2Fj -aDEVMBMGA1UEAxMMQ29ja3JvYWNoIENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAxdln3/UdgP7ayA/G1kT7upjLe4ERwQjYQ25q0e1+vgsB5jhiirxJ -e0+WkhhYu/mwoSAXzvlsbZ2PWFyfdanZeD/Lh6SvIeWXVVaPcWVWL1TEcoN2jr5+ -E85MMHmbbmaT2he8s6br2tM/UZxyTQ2XRprIzApbDssyw1c0Yufcpu3C6267FLEl -IfcWrzDhnluFhthhtGXv3ToD8IuMScMC5qlKBXtKmD1B5x14ngO/ecNJ+OlEi0HU -mavK4KWgI2rDXRZ2EnCpyTZdkc3kkRnzKcg653oOjMDRZdrhfIrha+Jq38ACsUmZ -Su7Sp5jkIHOCO8Zg+l6GKVSq37dKMapD8wIDAQABoyYwJDAOBgNVHQ8BAf8EBAMC -AuQwEgYDVR0TAQH/BAgwBgEB/wIBATANBgkqhkiG9w0BAQsFAAOCAQEAwZ2Tu0Yu -rrSVdMdoPEjT1IZd+5OhM/SLzL0ddtvTithRweLHsw2lDQYlXFqr24i3UGZJQ1sp -cqSrNwswgLUQT3vWyTjmM51HEb2vMYWKmjZ+sBQYAUP1CadrN/+OTfNGnlF1+B4w -IXOzh7EvQmJJnNybLe4a/aRvj1NE2n8Z898B76SVU9WbfKKz8VwLzuIPDqkKcZda -lMy5yzthyztV9YjcWs2zVOUGZvGdAhDrvZuUq6mSmxrBEvR2LBOggmVf3tGRT+Ls -lW7c9Lrva5zLHuqmoPP07A+vuI9a0D1X44jwGDuPWJ5RnTOQ63Uez12mKNjqleHw -DnkwNanuO8dhAA== ------END CERTIFICATE----- diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/postgresql.cnf b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/postgresql.cnf deleted file mode 100644 index fa8ffc489..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/postgresql.cnf +++ /dev/null @@ -1,10 +0,0 @@ -[req] -distinguished_name = req_distinguished_name -prompt = no - -[req_distinguished_name] -C = US -ST = Nevada -L = Las Vegas -O = github.com/lib/pq -CN = pqgosslcert diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/postgresql.crt b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/postgresql.crt deleted file mode 100644 index c1815f865..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/postgresql.crt +++ /dev/null @@ -1,20 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDPjCCAiYCCQD4nsC6zsmIqjANBgkqhkiG9w0BAQsFADBeMQswCQYDVQQGEwJV -UzEPMA0GA1UECAwGTmV2YWRhMRIwEAYDVQQHDAlMYXMgVmVnYXMxGjAYBgNVBAoM -EWdpdGh1Yi5jb20vbGliL3BxMQ4wDAYDVQQDDAVwcSBDQTAeFw0yMTA5MDIwMTU1 -MDJaFw0zMTA5MDMwMTU1MDJaMGQxCzAJBgNVBAYTAlVTMQ8wDQYDVQQIDAZOZXZh -ZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgGA1UECgwRZ2l0aHViLmNvbS9saWIv -cHExFDASBgNVBAMMC3BxZ29zc2xjZXJ0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAx0ucPVUNCrVmbyithwWrmmZ1dGudBwhSyDB6af4z5Cr+S6dx2SRU -UGUw3Lv+z+tUqQ7hJj0oNddIQeYKl/Tt6JPpZsQfERP/cUGedtyt7HnCKobBL+0B -NvHnDIUiIL4LgfiZK4DWJkGmm7nTHo/7qKAw60vCMLUW98DC0Xhlk9MHYG+e9Zai -3G0vY2X6DUYcSmzBI3JakFEgMZTQg3ofUQMz8TYeK3/DYadLXkl08d18LL3Dnefx -0xRuBPNTa2tLfVnFkfFi6Z9xVB/WhG6+X4OLnO85v5xUOGTV+g154iR7FOkrrl5F -lEUBj+yaIoTRi+MyZ/oYqWwQUDYS3+Te9wIDAQABMA0GCSqGSIb3DQEBCwUAA4IB -AQCCJpwUWCx7xfXv3vH3LQcffZycyRHYPgTCbiQw3x9aBb77jUAh5O6lEj/W0nx2 -SCTEsCsRSAiFwfUb+g/AFCW84dELRWmf38eoqACebLymqnvxyZA+O87yu07XyFZR -TnmbDMzZgsyWWGwS3JoGFk+ibWY4AImYQnSJO8Pi0kZ37ngbAyJ3RtDhhEQJWw/Q -D04p3uky/ea7Gyz0QTx5o40n4gq7nEzF1OS6IHozM840J5aZrxRiXEa56fsmJHmI -IGyI07SGlWJ15r1wc8lB+8ilnAqH1QQlYzTIW0Q4NZE7n3uQg1EVuueGiGO2ex2/ -he9lDiJfOQuPuLbOxzctP9v9 ------END CERTIFICATE----- diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/postgresql.key b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/postgresql.key deleted file mode 100644 index 8380da4bc..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/postgresql.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQDHS5w9VQ0KtWZv -KK2HBauaZnV0a50HCFLIMHpp/jPkKv5Lp3HZJFRQZTDcu/7P61SpDuEmPSg110hB -5gqX9O3ok+lmxB8RE/9xQZ523K3secIqhsEv7QE28ecMhSIgvguB+JkrgNYmQaab -udMej/uooDDrS8IwtRb3wMLReGWT0wdgb571lqLcbS9jZfoNRhxKbMEjclqQUSAx -lNCDeh9RAzPxNh4rf8Nhp0teSXTx3XwsvcOd5/HTFG4E81Nra0t9WcWR8WLpn3FU -H9aEbr5fg4uc7zm/nFQ4ZNX6DXniJHsU6SuuXkWURQGP7JoihNGL4zJn+hipbBBQ -NhLf5N73AgMBAAECggEAHLNY1sRO0oH5NHzpMI6yfdPPimqM/JxIP6grmOQQ2QUQ -BhkhHiJLOiC4frFcKtk7IfWQmw8noUlVkJfuYp/VOy9B55jK2IzGtqq6hWeWbH3E -Zpdtbtd021LO8VCi75Au3BLPDCLLtEq0Ea0bKEWX+lrHcLtCRf1uR1OtOrlZ94Wl -DUhm7YJC4cS1bi6Kdf03R+fw2oFi7/QdywcT4ow032jGWOly/Jl7bSHZK7xLtM/i -9HfMwmusD/iuz7mtLU7VCpnlKZm6MfS5D427ybW8MruuiZEtQJ6QtRIrHBHk93aK -Op0tjJ6tMav1UsJzgVz9+uWILE9l0AjAa4AvbfNzEQKBgQD8mma9SLQPtBb6cXuT -CQgjE4vyph8mRnm/pTz3QLIpMiLy2+aKJD/u4cduzLw1vjuH1tlb7NQ9c891jAJh -JhwDwqKAXfFicfRs/PYWngx/XtGhbbpgm1yA6XuYL1D06gzmjzXgHvZMOFcts+GF -y0JEuV7v6eYrpQJRQYCwY6xTgwKBgQDJ+bHAlgOaC94DZEXZMiUznCCjBjAstiXG -BEN7Cnfn6vgvPm/b6BkKn4VrsCmbZQKT7QJDSOhYwXCC2ZlrKiF8GEUHX4mi8347 -8B+DsuokTLNmN61QAZbb1c3XQVnr15xH8ijm7yYs4tCBmVLKBmpw1T4IZXXlVE5k -gmee+AwIfQKBgGr+P0wnclVAc4cq8CusZKzux5VEtebxbPo21CbqWUxHtzPk3rZe -elIFggK1Z3bgF7kG0NQ18QQCfLoOTqe1i6IwG8KBiA+pst1DHD0iPqroj6RvpMTs -qXbU7ovcZs8GH+a8fBZtJufL6WkrSvfvyybu2X6HNP4Bi4S9WPPdlA1fAoGAE5m/ -vkjQoKp2KS4Z+TH8mj2UjT2Uf0JN+CGByvcBG+iZnTwZ7uVfSMCiWgkGgKYU0fY2 -OgFhSvu6x3gGg3fbOAfC6yxCVyX6IibzZ/x87HjlEA5nK1R8J2lgSHt3FoQeDn1Z -qs+ajNCWG32doy1sNvb6xiXSgybjVK2zEKJRyKECgYBJTk2IABebjvInNb6tagcI -nD4d2LgBmZJZsTruHXrpO0s3XCQcFKks4JKH1CVjd34f7LkxzEOGbE7wKBBd652s -ob6gFKnbqTniTo3NRUycB6ymo4LSaBvKgeY5hYbVxrYheRLPGY+gPVYb3VMKu9N9 -76rcaFqJOz7OeywRG5bHUg== ------END PRIVATE KEY----- diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/root.cnf b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/root.cnf deleted file mode 100644 index ea6def267..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/root.cnf +++ /dev/null @@ -1,10 +0,0 @@ -[req] -distinguished_name = req_distinguished_name -prompt = no - -[req_distinguished_name] -C = US -ST = Nevada -L = Las Vegas -O = github.com/lib/pq -CN = pq CA diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/root.crt b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/root.crt deleted file mode 100644 index 390a907c3..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/root.crt +++ /dev/null @@ -1,24 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIEBjCCAu6gAwIBAgIJAPizR+OD14YnMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV -BAYTAlVTMQ8wDQYDVQQIDAZOZXZhZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgG -A1UECgwRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMMBXBxIENBMB4XDTIxMDkw -MjAxNTUwMloXDTMxMDkwMzAxNTUwMlowXjELMAkGA1UEBhMCVVMxDzANBgNVBAgM -Bk5ldmFkYTESMBAGA1UEBwwJTGFzIFZlZ2FzMRowGAYDVQQKDBFnaXRodWIuY29t -L2xpYi9wcTEOMAwGA1UEAwwFcHEgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw -ggEKAoIBAQDb9d6sjdU6GdibGrXRMOHREH3MRUS8T4TFqGgPEGVDP/V5bAZlBSGP -AN0o9DTyVLcbQpBt8zMTw9KeIzIIe5NIVkSmA16lw/YckGhOM+kZIkiDuE6qt5Ia -OQCRMdXkZ8ejG/JUu+rHU8FJZL8DE+jyYherzdjkeVAQ7JfzxAwW2Dl7T/47g337 -Pwmf17AEb8ibSqmXyUN7R5NhJQs+hvaYdNagzdx91E1H+qlyBvmiNeasUQljLvZ+ -Y8wAuU79neA+d09O4PBiYwV17rSP6SZCeGE3oLZviL/0KM9Xig88oB+2FmvQ6Zxa -L7SoBlqS+5pBZwpH7eee/wCIKAnJtMAJAgMBAAGjgcYwgcMwDwYDVR0TAQH/BAUw -AwEB/zAdBgNVHQ4EFgQUfIXEczahbcM2cFrwclJF7GbdajkwgZAGA1UdIwSBiDCB -hYAUfIXEczahbcM2cFrwclJF7GbdajmhYqRgMF4xCzAJBgNVBAYTAlVTMQ8wDQYD -VQQIDAZOZXZhZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgGA1UECgwRZ2l0aHVi -LmNvbS9saWIvcHExDjAMBgNVBAMMBXBxIENBggkA+LNH44PXhicwDQYJKoZIhvcN -AQELBQADggEBABFyGgSz2mHVJqYgX1Y+7P+MfKt83cV2uYDGYvXrLG2OGiCilVul -oTBG+8omIMSHOsQZvWMpA5H0tnnlQHrKpKpUyKkSL+Wv5GL0UtBmHX7mVRiaK2l4 -q2BjRaQUitp/FH4NSdXtVrMME5T1JBBZHsQkNL3cNRzRKwY/Vj5UGEDxDS7lILUC -e01L4oaK0iKQn4beALU+TvKoAHdPvoxpPpnhkF5ss9HmdcvRktJrKZemDJZswZ7/ -+omx8ZPIYYUH5VJJYYE88S7guAt+ZaKIUlel/t6xPbo2ZySFSg9u1uB99n+jTo3L -1rAxFnN3FCX2jBqgP29xMVmisaN5k04UmyI= ------END CERTIFICATE----- diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/server.cnf b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/server.cnf deleted file mode 100644 index ba4b55703..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/server.cnf +++ /dev/null @@ -1,29 +0,0 @@ -[ req ] -default_bits = 2048 -distinguished_name = subject -req_extensions = req_ext -x509_extensions = x509_ext -string_mask = utf8only -prompt = no - -[ subject ] -C = US -ST = Nevada -L = Las Vegas -O = github.com/lib/pq - -[ x509_ext ] -subjectKeyIdentifier = hash -authorityKeyIdentifier = keyid,issuer - -basicConstraints = CA:FALSE -keyUsage = digitalSignature, keyEncipherment -subjectAltName = DNS:postgres -nsComment = "OpenSSL Generated Certificate" - -[ req_ext ] -subjectKeyIdentifier = hash -basicConstraints = CA:FALSE -keyUsage = digitalSignature, keyEncipherment -subjectAltName = DNS:postgres -nsComment = "OpenSSL Generated Certificate" diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/server.crt b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/server.crt deleted file mode 100644 index 1a0ac0d43..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/server.crt +++ /dev/null @@ -1,22 +0,0 @@ ------BEGIN CERTIFICATE----- -MIIDqzCCApOgAwIBAgIJAPiewLrOyYipMA0GCSqGSIb3DQEBCwUAMF4xCzAJBgNV -BAYTAlVTMQ8wDQYDVQQIDAZOZXZhZGExEjAQBgNVBAcMCUxhcyBWZWdhczEaMBgG -A1UECgwRZ2l0aHViLmNvbS9saWIvcHExDjAMBgNVBAMMBXBxIENBMB4XDTIxMDkw -MjAxNTUwMloXDTMxMDkwMzAxNTUwMlowTjELMAkGA1UEBhMCVVMxDzANBgNVBAgM -Bk5ldmFkYTESMBAGA1UEBwwJTGFzIFZlZ2FzMRowGAYDVQQKDBFnaXRodWIuY29t -L2xpYi9wcTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKf6H4UzmANN -QiQJe92Mf3ETMYmpZKNNO9DPEHyNLIkag+XwMrBTdcCK0mLvsNCYpXuBN6703KCd -WAFOeMmj7gOsWtvjt5Xm6bRHLgegekXzcG/jDwq/wyzeDzr/YkITuIlG44Lf9lhY -FLwiHlHOWHnwrZaEh6aU//02aQkzyX5INeXl/3TZm2G2eIH6AOxOKOU27MUsyVSQ -5DE+SDKGcRP4bElueeQWvxAXNMZYb7sVSDdfHI3zr32K4k/tC8x0fZJ5XN/dvl4t -4N4MrYlmDO5XOrb/gQH1H4iu6+5EMDfZYab4fkThnNFdfFqu4/8Scv7KZ8mWqpKM -fGAjEPctQi0CAwEAAaN8MHowHQYDVR0OBBYEFENExPbmDyFB2AJUdbMvVyhlNPD5 -MAkGA1UdEwQCMAAwCwYDVR0PBAQDAgWgMBMGA1UdEQQMMAqCCHBvc3RncmVzMCwG -CWCGSAGG+EIBDQQfFh1PcGVuU1NMIEdlbmVyYXRlZCBDZXJ0aWZpY2F0ZTANBgkq -hkiG9w0BAQsFAAOCAQEAMRVbV8RiEsmp9HAtnVCZmRXMIbgPGrqjeSwk586s4K8v -BSqNCqxv6s5GfCRmDYiqSqeuCVDtUJS1HsTmbxVV7Ke71WMo+xHR1ICGKOa8WGCb -TGsuicG5QZXWaxeMOg4s0qpKmKko0d1aErdVsanU5dkrVS7D6729Ffnzu4lwApk6 -invAB67p8u7sojwqRq5ce0vRaG+YFylTrWomF9kauEb8gKbQ9Xc7QfX+h+UH/mq9 -Nvdj8LOHp6/82bZdnsYUOtV4lS1IA/qzeXpqBphxqfWabD1yLtkyJyImZKq8uIPp -0CG4jhObPdWcCkXD6bg3QK3mhwlC79OtFgxWmldCRQ== ------END CERTIFICATE----- diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/server.key b/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/server.key deleted file mode 100644 index 152e0f23e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/certs/server.key +++ /dev/null @@ -1,28 +0,0 @@ ------BEGIN PRIVATE KEY----- -MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCn+h+FM5gDTUIk -CXvdjH9xEzGJqWSjTTvQzxB8jSyJGoPl8DKwU3XAitJi77DQmKV7gTeu9NygnVgB -TnjJo+4DrFrb47eV5um0Ry4HoHpF83Bv4w8Kv8Ms3g86/2JCE7iJRuOC3/ZYWBS8 -Ih5Rzlh58K2WhIemlP/9NmkJM8l+SDXl5f902ZthtniB+gDsTijlNuzFLMlUkOQx -PkgyhnET+GxJbnnkFr8QFzTGWG+7FUg3XxyN8699iuJP7QvMdH2SeVzf3b5eLeDe -DK2JZgzuVzq2/4EB9R+IruvuRDA32WGm+H5E4ZzRXXxaruP/EnL+ymfJlqqSjHxg -IxD3LUItAgMBAAECggEAOE2naQ9tIZYw2EFxikZApVcooJrtx6ropMnzHbx4NBB2 -K4mChAXFj184u77ZxmGT/jzGvFcI6LE0wWNbK0NOUV7hKZk/fPhkV3AQZrAMrAu4 -IVi7PwAd3JkmA8F8XuebUDA5rDGDsgL8GD9baFJA58abeLs9eMGyuF4XgOUh4bip -hgHa76O2rcDWNY5HZqqRslw75FzlYkB0PCts/UJxSswj70kTTihyOhDlrm2TnyxI -ne54UbGRrpfs9wiheSGLjDG81qZToBHQDwoAnjjZhu1VCaBISuGbgZrxyyRyqdnn -xPW+KczMv04XyvF7v6Pz+bUEppalLXGiXnH5UtWvZQKBgQDTPCdMpNE/hwlq4nAw -Kf42zIBWfbnMLVWYoeDiAOhtl9XAUAXn76xe6Rvo0qeAo67yejdbJfRq3HvGyw+q -4PS8r9gXYmLYIPQxSoLL5+rFoBCN3qFippfjLB1j32mp7+15KjRj8FF2r6xIN8fu -XatSRsaqmvCWYLDRv/rbHnxwkwKBgQDLkyfFLF7BtwtPWKdqrwOM7ip1UKh+oDBS -vkCQ08aEFRBU7T3jChsx5GbaW6zmsSBwBwcrHclpSkz7n3aq19DDWObJR2p80Fma -rsXeIcvtEpkvT3pVX268P5d+XGs1kxgFunqTysG9yChW+xzcs5MdKBzuMPPn7rL8 -MKAzdar6PwKBgEypkzW8x3h/4Moa3k6MnwdyVs2NGaZheaRIc95yJ+jGZzxBjrMr -h+p2PbvU4BfO0AqOkpKRBtDVrlJqlggVVp04UHvEKE16QEW3Xhr0037f5cInX3j3 -Lz6yXwRFLAsR2aTUzWjL6jTh8uvO2s/GzQuyRh3a16Ar/WBShY+K0+zjAoGATnLT -xZjWnyHRmu8X/PWakamJ9RFzDPDgDlLAgM8LVgTj+UY/LgnL9wsEU6s2UuP5ExKy -QXxGDGwUhHar/SQTj+Pnc7Mwpw6HKSOmnnY5po8fNusSwml3O9XppEkrC0c236Y/ -7EobJO5IFVTJh4cv7vFxTJzSsRL8KFD4uzvh+nMCgYEAqY8NBYtIgNJA2B6C6hHF -+bG7v46434ZHFfGTmMQwzE4taVg7YRnzYESAlvK4bAP5ZXR90n7GRGFhrXzoMZ38 -r0bw/q9rV+ReGda7/Bjf7ciCKiq0RODcHtf4IaskjPXCoQRGJtgCPLhWPfld6g9v -/HTvO96xv9e3eG/PKSPog94= ------END PRIVATE KEY----- diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/conn.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/conn.go deleted file mode 100644 index e050d5358..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/conn.go +++ /dev/null @@ -1,2060 +0,0 @@ -package pq - -import ( - "bufio" - "context" - "crypto/md5" - "crypto/sha256" - "database/sql" - "database/sql/driver" - "encoding/binary" - "errors" - "fmt" - "io" - "net" - "os" - "os/user" - "path" - "path/filepath" - "strconv" - "strings" - "sync" - "time" - "unicode" - - "github.com/lib/pq/oid" - "github.com/lib/pq/scram" -) - -// Common error types -var ( - ErrNotSupported = errors.New("pq: Unsupported command") - ErrInFailedTransaction = errors.New("pq: Could not complete operation in a failed transaction") - ErrSSLNotSupported = errors.New("pq: SSL is not enabled on the server") - ErrSSLKeyHasWorldPermissions = errors.New("pq: Private key file has group or world access. Permissions should be u=rw (0600) or less") - ErrCouldNotDetectUsername = errors.New("pq: Could not detect default username. Please provide one explicitly") - - errUnexpectedReady = errors.New("unexpected ReadyForQuery") - errNoRowsAffected = errors.New("no RowsAffected available after the empty statement") - errNoLastInsertID = errors.New("no LastInsertId available after the empty statement") -) - -// Compile time validation that our types implement the expected interfaces -var ( - _ driver.Driver = Driver{} -) - -// Driver is the Postgres database driver. -type Driver struct{} - -// Open opens a new connection to the database. name is a connection string. -// Most users should only use it through database/sql package from the standard -// library. -func (d Driver) Open(name string) (driver.Conn, error) { - return Open(name) -} - -func init() { - sql.Register("postgres", &Driver{}) -} - -type parameterStatus struct { - // server version in the same format as server_version_num, or 0 if - // unavailable - serverVersion int - - // the current location based on the TimeZone value of the session, if - // available - currentLocation *time.Location -} - -type transactionStatus byte - -const ( - txnStatusIdle transactionStatus = 'I' - txnStatusIdleInTransaction transactionStatus = 'T' - txnStatusInFailedTransaction transactionStatus = 'E' -) - -func (s transactionStatus) String() string { - switch s { - case txnStatusIdle: - return "idle" - case txnStatusIdleInTransaction: - return "idle in transaction" - case txnStatusInFailedTransaction: - return "in a failed transaction" - default: - errorf("unknown transactionStatus %d", s) - } - - panic("not reached") -} - -// Dialer is the dialer interface. It can be used to obtain more control over -// how pq creates network connections. -type Dialer interface { - Dial(network, address string) (net.Conn, error) - DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) -} - -// DialerContext is the context-aware dialer interface. -type DialerContext interface { - DialContext(ctx context.Context, network, address string) (net.Conn, error) -} - -type defaultDialer struct { - d net.Dialer -} - -func (d defaultDialer) Dial(network, address string) (net.Conn, error) { - return d.d.Dial(network, address) -} -func (d defaultDialer) DialTimeout(network, address string, timeout time.Duration) (net.Conn, error) { - ctx, cancel := context.WithTimeout(context.Background(), timeout) - defer cancel() - return d.DialContext(ctx, network, address) -} -func (d defaultDialer) DialContext(ctx context.Context, network, address string) (net.Conn, error) { - return d.d.DialContext(ctx, network, address) -} - -type conn struct { - c net.Conn - buf *bufio.Reader - namei int - scratch [512]byte - txnStatus transactionStatus - txnFinish func() - - // Save connection arguments to use during CancelRequest. - dialer Dialer - opts values - - // Cancellation key data for use with CancelRequest messages. - processID int - secretKey int - - parameterStatus parameterStatus - - saveMessageType byte - saveMessageBuffer []byte - - // If an error is set, this connection is bad and all public-facing - // functions should return the appropriate error by calling get() - // (ErrBadConn) or getForNext(). - err syncErr - - // If set, this connection should never use the binary format when - // receiving query results from prepared statements. Only provided for - // debugging. - disablePreparedBinaryResult bool - - // Whether to always send []byte parameters over as binary. Enables single - // round-trip mode for non-prepared Query calls. - binaryParameters bool - - // If true this connection is in the middle of a COPY - inCopy bool - - // If not nil, notices will be synchronously sent here - noticeHandler func(*Error) - - // If not nil, notifications will be synchronously sent here - notificationHandler func(*Notification) - - // GSSAPI context - gss GSS -} - -type syncErr struct { - err error - sync.Mutex -} - -// Return ErrBadConn if connection is bad. -func (e *syncErr) get() error { - e.Lock() - defer e.Unlock() - if e.err != nil { - return driver.ErrBadConn - } - return nil -} - -// Return the error set on the connection. Currently only used by rows.Next. -func (e *syncErr) getForNext() error { - e.Lock() - defer e.Unlock() - return e.err -} - -// Set error, only if it isn't set yet. -func (e *syncErr) set(err error) { - if err == nil { - panic("attempt to set nil err") - } - e.Lock() - defer e.Unlock() - if e.err == nil { - e.err = err - } -} - -// Handle driver-side settings in parsed connection string. -func (cn *conn) handleDriverSettings(o values) (err error) { - boolSetting := func(key string, val *bool) error { - if value, ok := o[key]; ok { - if value == "yes" { - *val = true - } else if value == "no" { - *val = false - } else { - return fmt.Errorf("unrecognized value %q for %s", value, key) - } - } - return nil - } - - err = boolSetting("disable_prepared_binary_result", &cn.disablePreparedBinaryResult) - if err != nil { - return err - } - return boolSetting("binary_parameters", &cn.binaryParameters) -} - -func (cn *conn) handlePgpass(o values) { - // if a password was supplied, do not process .pgpass - if _, ok := o["password"]; ok { - return - } - filename := os.Getenv("PGPASSFILE") - if filename == "" { - // XXX this code doesn't work on Windows where the default filename is - // XXX %APPDATA%\postgresql\pgpass.conf - // Prefer $HOME over user.Current due to glibc bug: golang.org/issue/13470 - userHome := os.Getenv("HOME") - if userHome == "" { - user, err := user.Current() - if err != nil { - return - } - userHome = user.HomeDir - } - filename = filepath.Join(userHome, ".pgpass") - } - fileinfo, err := os.Stat(filename) - if err != nil { - return - } - mode := fileinfo.Mode() - if mode&(0x77) != 0 { - // XXX should warn about incorrect .pgpass permissions as psql does - return - } - file, err := os.Open(filename) - if err != nil { - return - } - defer file.Close() - scanner := bufio.NewScanner(io.Reader(file)) - hostname := o["host"] - ntw, _ := network(o) - port := o["port"] - db := o["dbname"] - username := o["user"] - // From: https://github.com/tg/pgpass/blob/master/reader.go - getFields := func(s string) []string { - fs := make([]string, 0, 5) - f := make([]rune, 0, len(s)) - - var esc bool - for _, c := range s { - switch { - case esc: - f = append(f, c) - esc = false - case c == '\\': - esc = true - case c == ':': - fs = append(fs, string(f)) - f = f[:0] - default: - f = append(f, c) - } - } - return append(fs, string(f)) - } - for scanner.Scan() { - line := scanner.Text() - if len(line) == 0 || line[0] == '#' { - continue - } - split := getFields(line) - if len(split) != 5 { - continue - } - if (split[0] == "*" || split[0] == hostname || (split[0] == "localhost" && (hostname == "" || ntw == "unix"))) && (split[1] == "*" || split[1] == port) && (split[2] == "*" || split[2] == db) && (split[3] == "*" || split[3] == username) { - o["password"] = split[4] - return - } - } -} - -func (cn *conn) writeBuf(b byte) *writeBuf { - cn.scratch[0] = b - return &writeBuf{ - buf: cn.scratch[:5], - pos: 1, - } -} - -// Open opens a new connection to the database. dsn is a connection string. -// Most users should only use it through database/sql package from the standard -// library. -func Open(dsn string) (_ driver.Conn, err error) { - return DialOpen(defaultDialer{}, dsn) -} - -// DialOpen opens a new connection to the database using a dialer. -func DialOpen(d Dialer, dsn string) (_ driver.Conn, err error) { - c, err := NewConnector(dsn) - if err != nil { - return nil, err - } - c.dialer = d - return c.open(context.Background()) -} - -func (c *Connector) open(ctx context.Context) (cn *conn, err error) { - // Handle any panics during connection initialization. Note that we - // specifically do *not* want to use errRecover(), as that would turn any - // connection errors into ErrBadConns, hiding the real error message from - // the user. - defer errRecoverNoErrBadConn(&err) - - // Create a new values map (copy). This makes it so maps in different - // connections do not reference the same underlying data structure, so it - // is safe for multiple connections to concurrently write to their opts. - o := make(values) - for k, v := range c.opts { - o[k] = v - } - - cn = &conn{ - opts: o, - dialer: c.dialer, - } - err = cn.handleDriverSettings(o) - if err != nil { - return nil, err - } - cn.handlePgpass(o) - - cn.c, err = dial(ctx, c.dialer, o) - if err != nil { - return nil, err - } - - err = cn.ssl(o) - if err != nil { - if cn.c != nil { - cn.c.Close() - } - return nil, err - } - - // cn.startup panics on error. Make sure we don't leak cn.c. - panicking := true - defer func() { - if panicking { - cn.c.Close() - } - }() - - cn.buf = bufio.NewReader(cn.c) - cn.startup(o) - - // reset the deadline, in case one was set (see dial) - if timeout, ok := o["connect_timeout"]; ok && timeout != "0" { - err = cn.c.SetDeadline(time.Time{}) - } - panicking = false - return cn, err -} - -func dial(ctx context.Context, d Dialer, o values) (net.Conn, error) { - network, address := network(o) - - // Zero or not specified means wait indefinitely. - if timeout, ok := o["connect_timeout"]; ok && timeout != "0" { - seconds, err := strconv.ParseInt(timeout, 10, 0) - if err != nil { - return nil, fmt.Errorf("invalid value for parameter connect_timeout: %s", err) - } - duration := time.Duration(seconds) * time.Second - - // connect_timeout should apply to the entire connection establishment - // procedure, so we both use a timeout for the TCP connection - // establishment and set a deadline for doing the initial handshake. - // The deadline is then reset after startup() is done. - deadline := time.Now().Add(duration) - var conn net.Conn - if dctx, ok := d.(DialerContext); ok { - ctx, cancel := context.WithTimeout(ctx, duration) - defer cancel() - conn, err = dctx.DialContext(ctx, network, address) - } else { - conn, err = d.DialTimeout(network, address, duration) - } - if err != nil { - return nil, err - } - err = conn.SetDeadline(deadline) - return conn, err - } - if dctx, ok := d.(DialerContext); ok { - return dctx.DialContext(ctx, network, address) - } - return d.Dial(network, address) -} - -func network(o values) (string, string) { - host := o["host"] - - if strings.HasPrefix(host, "/") { - sockPath := path.Join(host, ".s.PGSQL."+o["port"]) - return "unix", sockPath - } - - return "tcp", net.JoinHostPort(host, o["port"]) -} - -type values map[string]string - -// scanner implements a tokenizer for libpq-style option strings. -type scanner struct { - s []rune - i int -} - -// newScanner returns a new scanner initialized with the option string s. -func newScanner(s string) *scanner { - return &scanner{[]rune(s), 0} -} - -// Next returns the next rune. -// It returns 0, false if the end of the text has been reached. -func (s *scanner) Next() (rune, bool) { - if s.i >= len(s.s) { - return 0, false - } - r := s.s[s.i] - s.i++ - return r, true -} - -// SkipSpaces returns the next non-whitespace rune. -// It returns 0, false if the end of the text has been reached. -func (s *scanner) SkipSpaces() (rune, bool) { - r, ok := s.Next() - for unicode.IsSpace(r) && ok { - r, ok = s.Next() - } - return r, ok -} - -// parseOpts parses the options from name and adds them to the values. -// -// The parsing code is based on conninfo_parse from libpq's fe-connect.c -func parseOpts(name string, o values) error { - s := newScanner(name) - - for { - var ( - keyRunes, valRunes []rune - r rune - ok bool - ) - - if r, ok = s.SkipSpaces(); !ok { - break - } - - // Scan the key - for !unicode.IsSpace(r) && r != '=' { - keyRunes = append(keyRunes, r) - if r, ok = s.Next(); !ok { - break - } - } - - // Skip any whitespace if we're not at the = yet - if r != '=' { - r, ok = s.SkipSpaces() - } - - // The current character should be = - if r != '=' || !ok { - return fmt.Errorf(`missing "=" after %q in connection info string"`, string(keyRunes)) - } - - // Skip any whitespace after the = - if r, ok = s.SkipSpaces(); !ok { - // If we reach the end here, the last value is just an empty string as per libpq. - o[string(keyRunes)] = "" - break - } - - if r != '\'' { - for !unicode.IsSpace(r) { - if r == '\\' { - if r, ok = s.Next(); !ok { - return fmt.Errorf(`missing character after backslash`) - } - } - valRunes = append(valRunes, r) - - if r, ok = s.Next(); !ok { - break - } - } - } else { - quote: - for { - if r, ok = s.Next(); !ok { - return fmt.Errorf(`unterminated quoted string literal in connection string`) - } - switch r { - case '\'': - break quote - case '\\': - r, _ = s.Next() - fallthrough - default: - valRunes = append(valRunes, r) - } - } - } - - o[string(keyRunes)] = string(valRunes) - } - - return nil -} - -func (cn *conn) isInTransaction() bool { - return cn.txnStatus == txnStatusIdleInTransaction || - cn.txnStatus == txnStatusInFailedTransaction -} - -func (cn *conn) checkIsInTransaction(intxn bool) { - if cn.isInTransaction() != intxn { - cn.err.set(driver.ErrBadConn) - errorf("unexpected transaction status %v", cn.txnStatus) - } -} - -func (cn *conn) Begin() (_ driver.Tx, err error) { - return cn.begin("") -} - -func (cn *conn) begin(mode string) (_ driver.Tx, err error) { - if err := cn.err.get(); err != nil { - return nil, err - } - defer cn.errRecover(&err) - - cn.checkIsInTransaction(false) - _, commandTag, err := cn.simpleExec("BEGIN" + mode) - if err != nil { - return nil, err - } - if commandTag != "BEGIN" { - cn.err.set(driver.ErrBadConn) - return nil, fmt.Errorf("unexpected command tag %s", commandTag) - } - if cn.txnStatus != txnStatusIdleInTransaction { - cn.err.set(driver.ErrBadConn) - return nil, fmt.Errorf("unexpected transaction status %v", cn.txnStatus) - } - return cn, nil -} - -func (cn *conn) closeTxn() { - if finish := cn.txnFinish; finish != nil { - finish() - } -} - -func (cn *conn) Commit() (err error) { - defer cn.closeTxn() - if err := cn.err.get(); err != nil { - return err - } - defer cn.errRecover(&err) - - cn.checkIsInTransaction(true) - // We don't want the client to think that everything is okay if it tries - // to commit a failed transaction. However, no matter what we return, - // database/sql will release this connection back into the free connection - // pool so we have to abort the current transaction here. Note that you - // would get the same behaviour if you issued a COMMIT in a failed - // transaction, so it's also the least surprising thing to do here. - if cn.txnStatus == txnStatusInFailedTransaction { - if err := cn.rollback(); err != nil { - return err - } - return ErrInFailedTransaction - } - - _, commandTag, err := cn.simpleExec("COMMIT") - if err != nil { - if cn.isInTransaction() { - cn.err.set(driver.ErrBadConn) - } - return err - } - if commandTag != "COMMIT" { - cn.err.set(driver.ErrBadConn) - return fmt.Errorf("unexpected command tag %s", commandTag) - } - cn.checkIsInTransaction(false) - return nil -} - -func (cn *conn) Rollback() (err error) { - defer cn.closeTxn() - if err := cn.err.get(); err != nil { - return err - } - defer cn.errRecover(&err) - return cn.rollback() -} - -func (cn *conn) rollback() (err error) { - cn.checkIsInTransaction(true) - _, commandTag, err := cn.simpleExec("ROLLBACK") - if err != nil { - if cn.isInTransaction() { - cn.err.set(driver.ErrBadConn) - } - return err - } - if commandTag != "ROLLBACK" { - return fmt.Errorf("unexpected command tag %s", commandTag) - } - cn.checkIsInTransaction(false) - return nil -} - -func (cn *conn) gname() string { - cn.namei++ - return strconv.FormatInt(int64(cn.namei), 10) -} - -func (cn *conn) simpleExec(q string) (res driver.Result, commandTag string, err error) { - b := cn.writeBuf('Q') - b.string(q) - cn.send(b) - - for { - t, r := cn.recv1() - switch t { - case 'C': - res, commandTag = cn.parseComplete(r.string()) - case 'Z': - cn.processReadyForQuery(r) - if res == nil && err == nil { - err = errUnexpectedReady - } - // done - return - case 'E': - err = parseError(r) - case 'I': - res = emptyRows - case 'T', 'D': - // ignore any results - default: - cn.err.set(driver.ErrBadConn) - errorf("unknown response for simple query: %q", t) - } - } -} - -func (cn *conn) simpleQuery(q string) (res *rows, err error) { - defer cn.errRecover(&err) - - b := cn.writeBuf('Q') - b.string(q) - cn.send(b) - - for { - t, r := cn.recv1() - switch t { - case 'C', 'I': - // We allow queries which don't return any results through Query as - // well as Exec. We still have to give database/sql a rows object - // the user can close, though, to avoid connections from being - // leaked. A "rows" with done=true works fine for that purpose. - if err != nil { - cn.err.set(driver.ErrBadConn) - errorf("unexpected message %q in simple query execution", t) - } - if res == nil { - res = &rows{ - cn: cn, - } - } - // Set the result and tag to the last command complete if there wasn't a - // query already run. Although queries usually return from here and cede - // control to Next, a query with zero results does not. - if t == 'C' { - res.result, res.tag = cn.parseComplete(r.string()) - if res.colNames != nil { - return - } - } - res.done = true - case 'Z': - cn.processReadyForQuery(r) - // done - return - case 'E': - res = nil - err = parseError(r) - case 'D': - if res == nil { - cn.err.set(driver.ErrBadConn) - errorf("unexpected DataRow in simple query execution") - } - // the query didn't fail; kick off to Next - cn.saveMessage(t, r) - return - case 'T': - // res might be non-nil here if we received a previous - // CommandComplete, but that's fine; just overwrite it - res = &rows{cn: cn} - res.rowsHeader = parsePortalRowDescribe(r) - - // To work around a bug in QueryRow in Go 1.2 and earlier, wait - // until the first DataRow has been received. - default: - cn.err.set(driver.ErrBadConn) - errorf("unknown response for simple query: %q", t) - } - } -} - -type noRows struct{} - -var emptyRows noRows - -var _ driver.Result = noRows{} - -func (noRows) LastInsertId() (int64, error) { - return 0, errNoLastInsertID -} - -func (noRows) RowsAffected() (int64, error) { - return 0, errNoRowsAffected -} - -// Decides which column formats to use for a prepared statement. The input is -// an array of type oids, one element per result column. -func decideColumnFormats(colTyps []fieldDesc, forceText bool) (colFmts []format, colFmtData []byte) { - if len(colTyps) == 0 { - return nil, colFmtDataAllText - } - - colFmts = make([]format, len(colTyps)) - if forceText { - return colFmts, colFmtDataAllText - } - - allBinary := true - allText := true - for i, t := range colTyps { - switch t.OID { - // This is the list of types to use binary mode for when receiving them - // through a prepared statement. If a type appears in this list, it - // must also be implemented in binaryDecode in encode.go. - case oid.T_bytea: - fallthrough - case oid.T_int8: - fallthrough - case oid.T_int4: - fallthrough - case oid.T_int2: - fallthrough - case oid.T_uuid: - colFmts[i] = formatBinary - allText = false - - default: - allBinary = false - } - } - - if allBinary { - return colFmts, colFmtDataAllBinary - } else if allText { - return colFmts, colFmtDataAllText - } else { - colFmtData = make([]byte, 2+len(colFmts)*2) - binary.BigEndian.PutUint16(colFmtData, uint16(len(colFmts))) - for i, v := range colFmts { - binary.BigEndian.PutUint16(colFmtData[2+i*2:], uint16(v)) - } - return colFmts, colFmtData - } -} - -func (cn *conn) prepareTo(q, stmtName string) *stmt { - st := &stmt{cn: cn, name: stmtName} - - b := cn.writeBuf('P') - b.string(st.name) - b.string(q) - b.int16(0) - - b.next('D') - b.byte('S') - b.string(st.name) - - b.next('S') - cn.send(b) - - cn.readParseResponse() - st.paramTyps, st.colNames, st.colTyps = cn.readStatementDescribeResponse() - st.colFmts, st.colFmtData = decideColumnFormats(st.colTyps, cn.disablePreparedBinaryResult) - cn.readReadyForQuery() - return st -} - -func (cn *conn) Prepare(q string) (_ driver.Stmt, err error) { - if err := cn.err.get(); err != nil { - return nil, err - } - defer cn.errRecover(&err) - - if len(q) >= 4 && strings.EqualFold(q[:4], "COPY") { - s, err := cn.prepareCopyIn(q) - if err == nil { - cn.inCopy = true - } - return s, err - } - return cn.prepareTo(q, cn.gname()), nil -} - -func (cn *conn) Close() (err error) { - // Skip cn.bad return here because we always want to close a connection. - defer cn.errRecover(&err) - - // Ensure that cn.c.Close is always run. Since error handling is done with - // panics and cn.errRecover, the Close must be in a defer. - defer func() { - cerr := cn.c.Close() - if err == nil { - err = cerr - } - }() - - // Don't go through send(); ListenerConn relies on us not scribbling on the - // scratch buffer of this connection. - return cn.sendSimpleMessage('X') -} - -// Implement the "Queryer" interface -func (cn *conn) Query(query string, args []driver.Value) (driver.Rows, error) { - return cn.query(query, args) -} - -func (cn *conn) query(query string, args []driver.Value) (_ *rows, err error) { - if err := cn.err.get(); err != nil { - return nil, err - } - if cn.inCopy { - return nil, errCopyInProgress - } - defer cn.errRecover(&err) - - // Check to see if we can use the "simpleQuery" interface, which is - // *much* faster than going through prepare/exec - if len(args) == 0 { - return cn.simpleQuery(query) - } - - if cn.binaryParameters { - cn.sendBinaryModeQuery(query, args) - - cn.readParseResponse() - cn.readBindResponse() - rows := &rows{cn: cn} - rows.rowsHeader = cn.readPortalDescribeResponse() - cn.postExecuteWorkaround() - return rows, nil - } - st := cn.prepareTo(query, "") - st.exec(args) - return &rows{ - cn: cn, - rowsHeader: st.rowsHeader, - }, nil -} - -// Implement the optional "Execer" interface for one-shot queries -func (cn *conn) Exec(query string, args []driver.Value) (res driver.Result, err error) { - if err := cn.err.get(); err != nil { - return nil, err - } - defer cn.errRecover(&err) - - // Check to see if we can use the "simpleExec" interface, which is - // *much* faster than going through prepare/exec - if len(args) == 0 { - // ignore commandTag, our caller doesn't care - r, _, err := cn.simpleExec(query) - return r, err - } - - if cn.binaryParameters { - cn.sendBinaryModeQuery(query, args) - - cn.readParseResponse() - cn.readBindResponse() - cn.readPortalDescribeResponse() - cn.postExecuteWorkaround() - res, _, err = cn.readExecuteResponse("Execute") - return res, err - } - // Use the unnamed statement to defer planning until bind - // time, or else value-based selectivity estimates cannot be - // used. - st := cn.prepareTo(query, "") - r, err := st.Exec(args) - if err != nil { - panic(err) - } - return r, err -} - -type safeRetryError struct { - Err error -} - -func (se *safeRetryError) Error() string { - return se.Err.Error() -} - -func (cn *conn) send(m *writeBuf) { - n, err := cn.c.Write(m.wrap()) - if err != nil { - if n == 0 { - err = &safeRetryError{Err: err} - } - panic(err) - } -} - -func (cn *conn) sendStartupPacket(m *writeBuf) error { - _, err := cn.c.Write((m.wrap())[1:]) - return err -} - -// Send a message of type typ to the server on the other end of cn. The -// message should have no payload. This method does not use the scratch -// buffer. -func (cn *conn) sendSimpleMessage(typ byte) (err error) { - _, err = cn.c.Write([]byte{typ, '\x00', '\x00', '\x00', '\x04'}) - return err -} - -// saveMessage memorizes a message and its buffer in the conn struct. -// recvMessage will then return these values on the next call to it. This -// method is useful in cases where you have to see what the next message is -// going to be (e.g. to see whether it's an error or not) but you can't handle -// the message yourself. -func (cn *conn) saveMessage(typ byte, buf *readBuf) { - if cn.saveMessageType != 0 { - cn.err.set(driver.ErrBadConn) - errorf("unexpected saveMessageType %d", cn.saveMessageType) - } - cn.saveMessageType = typ - cn.saveMessageBuffer = *buf -} - -// recvMessage receives any message from the backend, or returns an error if -// a problem occurred while reading the message. -func (cn *conn) recvMessage(r *readBuf) (byte, error) { - // workaround for a QueryRow bug, see exec - if cn.saveMessageType != 0 { - t := cn.saveMessageType - *r = cn.saveMessageBuffer - cn.saveMessageType = 0 - cn.saveMessageBuffer = nil - return t, nil - } - - x := cn.scratch[:5] - _, err := io.ReadFull(cn.buf, x) - if err != nil { - return 0, err - } - - // read the type and length of the message that follows - t := x[0] - n := int(binary.BigEndian.Uint32(x[1:])) - 4 - var y []byte - if n <= len(cn.scratch) { - y = cn.scratch[:n] - } else { - y = make([]byte, n) - } - _, err = io.ReadFull(cn.buf, y) - if err != nil { - return 0, err - } - *r = y - return t, nil -} - -// recv receives a message from the backend, but if an error happened while -// reading the message or the received message was an ErrorResponse, it panics. -// NoticeResponses are ignored. This function should generally be used only -// during the startup sequence. -func (cn *conn) recv() (t byte, r *readBuf) { - for { - var err error - r = &readBuf{} - t, err = cn.recvMessage(r) - if err != nil { - panic(err) - } - switch t { - case 'E': - panic(parseError(r)) - case 'N': - if n := cn.noticeHandler; n != nil { - n(parseError(r)) - } - case 'A': - if n := cn.notificationHandler; n != nil { - n(recvNotification(r)) - } - default: - return - } - } -} - -// recv1Buf is exactly equivalent to recv1, except it uses a buffer supplied by -// the caller to avoid an allocation. -func (cn *conn) recv1Buf(r *readBuf) byte { - for { - t, err := cn.recvMessage(r) - if err != nil { - panic(err) - } - - switch t { - case 'A': - if n := cn.notificationHandler; n != nil { - n(recvNotification(r)) - } - case 'N': - if n := cn.noticeHandler; n != nil { - n(parseError(r)) - } - case 'S': - cn.processParameterStatus(r) - default: - return t - } - } -} - -// recv1 receives a message from the backend, panicking if an error occurs -// while attempting to read it. All asynchronous messages are ignored, with -// the exception of ErrorResponse. -func (cn *conn) recv1() (t byte, r *readBuf) { - r = &readBuf{} - t = cn.recv1Buf(r) - return t, r -} - -func (cn *conn) ssl(o values) error { - upgrade, err := ssl(o) - if err != nil { - return err - } - - if upgrade == nil { - // Nothing to do - return nil - } - - w := cn.writeBuf(0) - w.int32(80877103) - if err = cn.sendStartupPacket(w); err != nil { - return err - } - - b := cn.scratch[:1] - _, err = io.ReadFull(cn.c, b) - if err != nil { - return err - } - - if b[0] != 'S' { - return ErrSSLNotSupported - } - - cn.c, err = upgrade(cn.c) - return err -} - -// isDriverSetting returns true iff a setting is purely for configuring the -// driver's options and should not be sent to the server in the connection -// startup packet. -func isDriverSetting(key string) bool { - switch key { - case "host", "port": - return true - case "password": - return true - case "sslmode", "sslcert", "sslkey", "sslrootcert", "sslinline": - return true - case "fallback_application_name": - return true - case "connect_timeout": - return true - case "disable_prepared_binary_result": - return true - case "binary_parameters": - return true - case "krbsrvname": - return true - case "krbspn": - return true - default: - return false - } -} - -func (cn *conn) startup(o values) { - w := cn.writeBuf(0) - w.int32(196608) - // Send the backend the name of the database we want to connect to, and the - // user we want to connect as. Additionally, we send over any run-time - // parameters potentially included in the connection string. If the server - // doesn't recognize any of them, it will reply with an error. - for k, v := range o { - if isDriverSetting(k) { - // skip options which can't be run-time parameters - continue - } - // The protocol requires us to supply the database name as "database" - // instead of "dbname". - if k == "dbname" { - k = "database" - } - w.string(k) - w.string(v) - } - w.string("") - if err := cn.sendStartupPacket(w); err != nil { - panic(err) - } - - for { - t, r := cn.recv() - switch t { - case 'K': - cn.processBackendKeyData(r) - case 'S': - cn.processParameterStatus(r) - case 'R': - cn.auth(r, o) - case 'Z': - cn.processReadyForQuery(r) - return - default: - errorf("unknown response for startup: %q", t) - } - } -} - -func (cn *conn) auth(r *readBuf, o values) { - switch code := r.int32(); code { - case 0: - // OK - case 3: - w := cn.writeBuf('p') - w.string(o["password"]) - cn.send(w) - - t, r := cn.recv() - if t != 'R' { - errorf("unexpected password response: %q", t) - } - - if r.int32() != 0 { - errorf("unexpected authentication response: %q", t) - } - case 5: - s := string(r.next(4)) - w := cn.writeBuf('p') - w.string("md5" + md5s(md5s(o["password"]+o["user"])+s)) - cn.send(w) - - t, r := cn.recv() - if t != 'R' { - errorf("unexpected password response: %q", t) - } - - if r.int32() != 0 { - errorf("unexpected authentication response: %q", t) - } - case 7: // GSSAPI, startup - if newGss == nil { - errorf("kerberos error: no GSSAPI provider registered (import github.com/lib/pq/auth/kerberos if you need Kerberos support)") - } - cli, err := newGss() - if err != nil { - errorf("kerberos error: %s", err.Error()) - } - - var token []byte - - if spn, ok := o["krbspn"]; ok { - // Use the supplied SPN if provided.. - token, err = cli.GetInitTokenFromSpn(spn) - } else { - // Allow the kerberos service name to be overridden - service := "postgres" - if val, ok := o["krbsrvname"]; ok { - service = val - } - - token, err = cli.GetInitToken(o["host"], service) - } - - if err != nil { - errorf("failed to get Kerberos ticket: %q", err) - } - - w := cn.writeBuf('p') - w.bytes(token) - cn.send(w) - - // Store for GSSAPI continue message - cn.gss = cli - - case 8: // GSSAPI continue - - if cn.gss == nil { - errorf("GSSAPI protocol error") - } - - b := []byte(*r) - - done, tokOut, err := cn.gss.Continue(b) - if err == nil && !done { - w := cn.writeBuf('p') - w.bytes(tokOut) - cn.send(w) - } - - // Errors fall through and read the more detailed message - // from the server.. - - case 10: - sc := scram.NewClient(sha256.New, o["user"], o["password"]) - sc.Step(nil) - if sc.Err() != nil { - errorf("SCRAM-SHA-256 error: %s", sc.Err().Error()) - } - scOut := sc.Out() - - w := cn.writeBuf('p') - w.string("SCRAM-SHA-256") - w.int32(len(scOut)) - w.bytes(scOut) - cn.send(w) - - t, r := cn.recv() - if t != 'R' { - errorf("unexpected password response: %q", t) - } - - if r.int32() != 11 { - errorf("unexpected authentication response: %q", t) - } - - nextStep := r.next(len(*r)) - sc.Step(nextStep) - if sc.Err() != nil { - errorf("SCRAM-SHA-256 error: %s", sc.Err().Error()) - } - - scOut = sc.Out() - w = cn.writeBuf('p') - w.bytes(scOut) - cn.send(w) - - t, r = cn.recv() - if t != 'R' { - errorf("unexpected password response: %q", t) - } - - if r.int32() != 12 { - errorf("unexpected authentication response: %q", t) - } - - nextStep = r.next(len(*r)) - sc.Step(nextStep) - if sc.Err() != nil { - errorf("SCRAM-SHA-256 error: %s", sc.Err().Error()) - } - - default: - errorf("unknown authentication response: %d", code) - } -} - -type format int - -const formatText format = 0 -const formatBinary format = 1 - -// One result-column format code with the value 1 (i.e. all binary). -var colFmtDataAllBinary = []byte{0, 1, 0, 1} - -// No result-column format codes (i.e. all text). -var colFmtDataAllText = []byte{0, 0} - -type stmt struct { - cn *conn - name string - rowsHeader - colFmtData []byte - paramTyps []oid.Oid - closed bool -} - -func (st *stmt) Close() (err error) { - if st.closed { - return nil - } - if err := st.cn.err.get(); err != nil { - return err - } - defer st.cn.errRecover(&err) - - w := st.cn.writeBuf('C') - w.byte('S') - w.string(st.name) - st.cn.send(w) - - st.cn.send(st.cn.writeBuf('S')) - - t, _ := st.cn.recv1() - if t != '3' { - st.cn.err.set(driver.ErrBadConn) - errorf("unexpected close response: %q", t) - } - st.closed = true - - t, r := st.cn.recv1() - if t != 'Z' { - st.cn.err.set(driver.ErrBadConn) - errorf("expected ready for query, but got: %q", t) - } - st.cn.processReadyForQuery(r) - - return nil -} - -func (st *stmt) Query(v []driver.Value) (r driver.Rows, err error) { - return st.query(v) -} - -func (st *stmt) query(v []driver.Value) (r *rows, err error) { - if err := st.cn.err.get(); err != nil { - return nil, err - } - defer st.cn.errRecover(&err) - - st.exec(v) - return &rows{ - cn: st.cn, - rowsHeader: st.rowsHeader, - }, nil -} - -func (st *stmt) Exec(v []driver.Value) (res driver.Result, err error) { - if err := st.cn.err.get(); err != nil { - return nil, err - } - defer st.cn.errRecover(&err) - - st.exec(v) - res, _, err = st.cn.readExecuteResponse("simple query") - return res, err -} - -func (st *stmt) exec(v []driver.Value) { - if len(v) >= 65536 { - errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(v)) - } - if len(v) != len(st.paramTyps) { - errorf("got %d parameters but the statement requires %d", len(v), len(st.paramTyps)) - } - - cn := st.cn - w := cn.writeBuf('B') - w.byte(0) // unnamed portal - w.string(st.name) - - if cn.binaryParameters { - cn.sendBinaryParameters(w, v) - } else { - w.int16(0) - w.int16(len(v)) - for i, x := range v { - if x == nil { - w.int32(-1) - } else { - b := encode(&cn.parameterStatus, x, st.paramTyps[i]) - w.int32(len(b)) - w.bytes(b) - } - } - } - w.bytes(st.colFmtData) - - w.next('E') - w.byte(0) - w.int32(0) - - w.next('S') - cn.send(w) - - cn.readBindResponse() - cn.postExecuteWorkaround() - -} - -func (st *stmt) NumInput() int { - return len(st.paramTyps) -} - -// parseComplete parses the "command tag" from a CommandComplete message, and -// returns the number of rows affected (if applicable) and a string -// identifying only the command that was executed, e.g. "ALTER TABLE". If the -// command tag could not be parsed, parseComplete panics. -func (cn *conn) parseComplete(commandTag string) (driver.Result, string) { - commandsWithAffectedRows := []string{ - "SELECT ", - // INSERT is handled below - "UPDATE ", - "DELETE ", - "FETCH ", - "MOVE ", - "COPY ", - } - - var affectedRows *string - for _, tag := range commandsWithAffectedRows { - if strings.HasPrefix(commandTag, tag) { - t := commandTag[len(tag):] - affectedRows = &t - commandTag = tag[:len(tag)-1] - break - } - } - // INSERT also includes the oid of the inserted row in its command tag. - // Oids in user tables are deprecated, and the oid is only returned when - // exactly one row is inserted, so it's unlikely to be of value to any - // real-world application and we can ignore it. - if affectedRows == nil && strings.HasPrefix(commandTag, "INSERT ") { - parts := strings.Split(commandTag, " ") - if len(parts) != 3 { - cn.err.set(driver.ErrBadConn) - errorf("unexpected INSERT command tag %s", commandTag) - } - affectedRows = &parts[len(parts)-1] - commandTag = "INSERT" - } - // There should be no affected rows attached to the tag, just return it - if affectedRows == nil { - return driver.RowsAffected(0), commandTag - } - n, err := strconv.ParseInt(*affectedRows, 10, 64) - if err != nil { - cn.err.set(driver.ErrBadConn) - errorf("could not parse commandTag: %s", err) - } - return driver.RowsAffected(n), commandTag -} - -type rowsHeader struct { - colNames []string - colTyps []fieldDesc - colFmts []format -} - -type rows struct { - cn *conn - finish func() - rowsHeader - done bool - rb readBuf - result driver.Result - tag string - - next *rowsHeader -} - -func (rs *rows) Close() error { - if finish := rs.finish; finish != nil { - defer finish() - } - // no need to look at cn.bad as Next() will - for { - err := rs.Next(nil) - switch err { - case nil: - case io.EOF: - // rs.Next can return io.EOF on both 'Z' (ready for query) and 'T' (row - // description, used with HasNextResultSet). We need to fetch messages until - // we hit a 'Z', which is done by waiting for done to be set. - if rs.done { - return nil - } - default: - return err - } - } -} - -func (rs *rows) Columns() []string { - return rs.colNames -} - -func (rs *rows) Result() driver.Result { - if rs.result == nil { - return emptyRows - } - return rs.result -} - -func (rs *rows) Tag() string { - return rs.tag -} - -func (rs *rows) Next(dest []driver.Value) (err error) { - if rs.done { - return io.EOF - } - - conn := rs.cn - if err := conn.err.getForNext(); err != nil { - return err - } - defer conn.errRecover(&err) - - for { - t := conn.recv1Buf(&rs.rb) - switch t { - case 'E': - err = parseError(&rs.rb) - case 'C', 'I': - if t == 'C' { - rs.result, rs.tag = conn.parseComplete(rs.rb.string()) - } - continue - case 'Z': - conn.processReadyForQuery(&rs.rb) - rs.done = true - if err != nil { - return err - } - return io.EOF - case 'D': - n := rs.rb.int16() - if err != nil { - conn.err.set(driver.ErrBadConn) - errorf("unexpected DataRow after error %s", err) - } - if n < len(dest) { - dest = dest[:n] - } - for i := range dest { - l := rs.rb.int32() - if l == -1 { - dest[i] = nil - continue - } - dest[i] = decode(&conn.parameterStatus, rs.rb.next(l), rs.colTyps[i].OID, rs.colFmts[i]) - } - return - case 'T': - next := parsePortalRowDescribe(&rs.rb) - rs.next = &next - return io.EOF - default: - errorf("unexpected message after execute: %q", t) - } - } -} - -func (rs *rows) HasNextResultSet() bool { - hasNext := rs.next != nil && !rs.done - return hasNext -} - -func (rs *rows) NextResultSet() error { - if rs.next == nil { - return io.EOF - } - rs.rowsHeader = *rs.next - rs.next = nil - return nil -} - -// QuoteIdentifier quotes an "identifier" (e.g. a table or a column name) to be -// used as part of an SQL statement. For example: -// -// tblname := "my_table" -// data := "my_data" -// quoted := pq.QuoteIdentifier(tblname) -// err := db.Exec(fmt.Sprintf("INSERT INTO %s VALUES ($1)", quoted), data) -// -// Any double quotes in name will be escaped. The quoted identifier will be -// case sensitive when used in a query. If the input string contains a zero -// byte, the result will be truncated immediately before it. -func QuoteIdentifier(name string) string { - end := strings.IndexRune(name, 0) - if end > -1 { - name = name[:end] - } - return `"` + strings.Replace(name, `"`, `""`, -1) + `"` -} - -// QuoteLiteral quotes a 'literal' (e.g. a parameter, often used to pass literal -// to DDL and other statements that do not accept parameters) to be used as part -// of an SQL statement. For example: -// -// exp_date := pq.QuoteLiteral("2023-01-05 15:00:00Z") -// err := db.Exec(fmt.Sprintf("CREATE ROLE my_user VALID UNTIL %s", exp_date)) -// -// Any single quotes in name will be escaped. Any backslashes (i.e. "\") will be -// replaced by two backslashes (i.e. "\\") and the C-style escape identifier -// that PostgreSQL provides ('E') will be prepended to the string. -func QuoteLiteral(literal string) string { - // This follows the PostgreSQL internal algorithm for handling quoted literals - // from libpq, which can be found in the "PQEscapeStringInternal" function, - // which is found in the libpq/fe-exec.c source file: - // https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/interfaces/libpq/fe-exec.c - // - // substitute any single-quotes (') with two single-quotes ('') - literal = strings.Replace(literal, `'`, `''`, -1) - // determine if the string has any backslashes (\) in it. - // if it does, replace any backslashes (\) with two backslashes (\\) - // then, we need to wrap the entire string with a PostgreSQL - // C-style escape. Per how "PQEscapeStringInternal" handles this case, we - // also add a space before the "E" - if strings.Contains(literal, `\`) { - literal = strings.Replace(literal, `\`, `\\`, -1) - literal = ` E'` + literal + `'` - } else { - // otherwise, we can just wrap the literal with a pair of single quotes - literal = `'` + literal + `'` - } - return literal -} - -func md5s(s string) string { - h := md5.New() - h.Write([]byte(s)) - return fmt.Sprintf("%x", h.Sum(nil)) -} - -func (cn *conn) sendBinaryParameters(b *writeBuf, args []driver.Value) { - // Do one pass over the parameters to see if we're going to send any of - // them over in binary. If we are, create a paramFormats array at the - // same time. - var paramFormats []int - for i, x := range args { - _, ok := x.([]byte) - if ok { - if paramFormats == nil { - paramFormats = make([]int, len(args)) - } - paramFormats[i] = 1 - } - } - if paramFormats == nil { - b.int16(0) - } else { - b.int16(len(paramFormats)) - for _, x := range paramFormats { - b.int16(x) - } - } - - b.int16(len(args)) - for _, x := range args { - if x == nil { - b.int32(-1) - } else { - datum := binaryEncode(&cn.parameterStatus, x) - b.int32(len(datum)) - b.bytes(datum) - } - } -} - -func (cn *conn) sendBinaryModeQuery(query string, args []driver.Value) { - if len(args) >= 65536 { - errorf("got %d parameters but PostgreSQL only supports 65535 parameters", len(args)) - } - - b := cn.writeBuf('P') - b.byte(0) // unnamed statement - b.string(query) - b.int16(0) - - b.next('B') - b.int16(0) // unnamed portal and statement - cn.sendBinaryParameters(b, args) - b.bytes(colFmtDataAllText) - - b.next('D') - b.byte('P') - b.byte(0) // unnamed portal - - b.next('E') - b.byte(0) - b.int32(0) - - b.next('S') - cn.send(b) -} - -func (cn *conn) processParameterStatus(r *readBuf) { - var err error - - param := r.string() - switch param { - case "server_version": - var major1 int - var major2 int - _, err = fmt.Sscanf(r.string(), "%d.%d", &major1, &major2) - if err == nil { - cn.parameterStatus.serverVersion = major1*10000 + major2*100 - } - - case "TimeZone": - cn.parameterStatus.currentLocation, err = time.LoadLocation(r.string()) - if err != nil { - cn.parameterStatus.currentLocation = nil - } - - default: - // ignore - } -} - -func (cn *conn) processReadyForQuery(r *readBuf) { - cn.txnStatus = transactionStatus(r.byte()) -} - -func (cn *conn) readReadyForQuery() { - t, r := cn.recv1() - switch t { - case 'Z': - cn.processReadyForQuery(r) - return - default: - cn.err.set(driver.ErrBadConn) - errorf("unexpected message %q; expected ReadyForQuery", t) - } -} - -func (cn *conn) processBackendKeyData(r *readBuf) { - cn.processID = r.int32() - cn.secretKey = r.int32() -} - -func (cn *conn) readParseResponse() { - t, r := cn.recv1() - switch t { - case '1': - return - case 'E': - err := parseError(r) - cn.readReadyForQuery() - panic(err) - default: - cn.err.set(driver.ErrBadConn) - errorf("unexpected Parse response %q", t) - } -} - -func (cn *conn) readStatementDescribeResponse() (paramTyps []oid.Oid, colNames []string, colTyps []fieldDesc) { - for { - t, r := cn.recv1() - switch t { - case 't': - nparams := r.int16() - paramTyps = make([]oid.Oid, nparams) - for i := range paramTyps { - paramTyps[i] = r.oid() - } - case 'n': - return paramTyps, nil, nil - case 'T': - colNames, colTyps = parseStatementRowDescribe(r) - return paramTyps, colNames, colTyps - case 'E': - err := parseError(r) - cn.readReadyForQuery() - panic(err) - default: - cn.err.set(driver.ErrBadConn) - errorf("unexpected Describe statement response %q", t) - } - } -} - -func (cn *conn) readPortalDescribeResponse() rowsHeader { - t, r := cn.recv1() - switch t { - case 'T': - return parsePortalRowDescribe(r) - case 'n': - return rowsHeader{} - case 'E': - err := parseError(r) - cn.readReadyForQuery() - panic(err) - default: - cn.err.set(driver.ErrBadConn) - errorf("unexpected Describe response %q", t) - } - panic("not reached") -} - -func (cn *conn) readBindResponse() { - t, r := cn.recv1() - switch t { - case '2': - return - case 'E': - err := parseError(r) - cn.readReadyForQuery() - panic(err) - default: - cn.err.set(driver.ErrBadConn) - errorf("unexpected Bind response %q", t) - } -} - -func (cn *conn) postExecuteWorkaround() { - // Work around a bug in sql.DB.QueryRow: in Go 1.2 and earlier it ignores - // any errors from rows.Next, which masks errors that happened during the - // execution of the query. To avoid the problem in common cases, we wait - // here for one more message from the database. If it's not an error the - // query will likely succeed (or perhaps has already, if it's a - // CommandComplete), so we push the message into the conn struct; recv1 - // will return it as the next message for rows.Next or rows.Close. - // However, if it's an error, we wait until ReadyForQuery and then return - // the error to our caller. - for { - t, r := cn.recv1() - switch t { - case 'E': - err := parseError(r) - cn.readReadyForQuery() - panic(err) - case 'C', 'D', 'I': - // the query didn't fail, but we can't process this message - cn.saveMessage(t, r) - return - default: - cn.err.set(driver.ErrBadConn) - errorf("unexpected message during extended query execution: %q", t) - } - } -} - -// Only for Exec(), since we ignore the returned data -func (cn *conn) readExecuteResponse(protocolState string) (res driver.Result, commandTag string, err error) { - for { - t, r := cn.recv1() - switch t { - case 'C': - if err != nil { - cn.err.set(driver.ErrBadConn) - errorf("unexpected CommandComplete after error %s", err) - } - res, commandTag = cn.parseComplete(r.string()) - case 'Z': - cn.processReadyForQuery(r) - if res == nil && err == nil { - err = errUnexpectedReady - } - return res, commandTag, err - case 'E': - err = parseError(r) - case 'T', 'D', 'I': - if err != nil { - cn.err.set(driver.ErrBadConn) - errorf("unexpected %q after error %s", t, err) - } - if t == 'I' { - res = emptyRows - } - // ignore any results - default: - cn.err.set(driver.ErrBadConn) - errorf("unknown %s response: %q", protocolState, t) - } - } -} - -func parseStatementRowDescribe(r *readBuf) (colNames []string, colTyps []fieldDesc) { - n := r.int16() - colNames = make([]string, n) - colTyps = make([]fieldDesc, n) - for i := range colNames { - colNames[i] = r.string() - r.next(6) - colTyps[i].OID = r.oid() - colTyps[i].Len = r.int16() - colTyps[i].Mod = r.int32() - // format code not known when describing a statement; always 0 - r.next(2) - } - return -} - -func parsePortalRowDescribe(r *readBuf) rowsHeader { - n := r.int16() - colNames := make([]string, n) - colFmts := make([]format, n) - colTyps := make([]fieldDesc, n) - for i := range colNames { - colNames[i] = r.string() - r.next(6) - colTyps[i].OID = r.oid() - colTyps[i].Len = r.int16() - colTyps[i].Mod = r.int32() - colFmts[i] = format(r.int16()) - } - return rowsHeader{ - colNames: colNames, - colFmts: colFmts, - colTyps: colTyps, - } -} - -// parseEnviron tries to mimic some of libpq's environment handling -// -// To ease testing, it does not directly reference os.Environ, but is -// designed to accept its output. -// -// Environment-set connection information is intended to have a higher -// precedence than a library default but lower than any explicitly -// passed information (such as in the URL or connection string). -func parseEnviron(env []string) (out map[string]string) { - out = make(map[string]string) - - for _, v := range env { - parts := strings.SplitN(v, "=", 2) - - accrue := func(keyname string) { - out[keyname] = parts[1] - } - unsupported := func() { - panic(fmt.Sprintf("setting %v not supported", parts[0])) - } - - // The order of these is the same as is seen in the - // PostgreSQL 9.1 manual. Unsupported but well-defined - // keys cause a panic; these should be unset prior to - // execution. Options which pq expects to be set to a - // certain value are allowed, but must be set to that - // value if present (they can, of course, be absent). - switch parts[0] { - case "PGHOST": - accrue("host") - case "PGHOSTADDR": - unsupported() - case "PGPORT": - accrue("port") - case "PGDATABASE": - accrue("dbname") - case "PGUSER": - accrue("user") - case "PGPASSWORD": - accrue("password") - case "PGSERVICE", "PGSERVICEFILE", "PGREALM": - unsupported() - case "PGOPTIONS": - accrue("options") - case "PGAPPNAME": - accrue("application_name") - case "PGSSLMODE": - accrue("sslmode") - case "PGSSLCERT": - accrue("sslcert") - case "PGSSLKEY": - accrue("sslkey") - case "PGSSLROOTCERT": - accrue("sslrootcert") - case "PGREQUIRESSL", "PGSSLCRL": - unsupported() - case "PGREQUIREPEER": - unsupported() - case "PGKRBSRVNAME", "PGGSSLIB": - unsupported() - case "PGCONNECT_TIMEOUT": - accrue("connect_timeout") - case "PGCLIENTENCODING": - accrue("client_encoding") - case "PGDATESTYLE": - accrue("datestyle") - case "PGTZ": - accrue("timezone") - case "PGGEQO": - accrue("geqo") - case "PGSYSCONFDIR", "PGLOCALEDIR": - unsupported() - } - } - - return out -} - -// isUTF8 returns whether name is a fuzzy variation of the string "UTF-8". -func isUTF8(name string) bool { - // Recognize all sorts of silly things as "UTF-8", like Postgres does - s := strings.Map(alnumLowerASCII, name) - return s == "utf8" || s == "unicode" -} - -func alnumLowerASCII(ch rune) rune { - if 'A' <= ch && ch <= 'Z' { - return ch + ('a' - 'A') - } - if 'a' <= ch && ch <= 'z' || '0' <= ch && ch <= '9' { - return ch - } - return -1 // discard -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/conn_go18.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/conn_go18.go deleted file mode 100644 index 63d4ca6aa..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/conn_go18.go +++ /dev/null @@ -1,247 +0,0 @@ -package pq - -import ( - "context" - "database/sql" - "database/sql/driver" - "fmt" - "io" - "io/ioutil" - "time" -) - -const ( - watchCancelDialContextTimeout = time.Second * 10 -) - -// Implement the "QueryerContext" interface -func (cn *conn) QueryContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Rows, error) { - list := make([]driver.Value, len(args)) - for i, nv := range args { - list[i] = nv.Value - } - finish := cn.watchCancel(ctx) - r, err := cn.query(query, list) - if err != nil { - if finish != nil { - finish() - } - return nil, err - } - r.finish = finish - return r, nil -} - -// Implement the "ExecerContext" interface -func (cn *conn) ExecContext(ctx context.Context, query string, args []driver.NamedValue) (driver.Result, error) { - list := make([]driver.Value, len(args)) - for i, nv := range args { - list[i] = nv.Value - } - - if finish := cn.watchCancel(ctx); finish != nil { - defer finish() - } - - return cn.Exec(query, list) -} - -// Implement the "ConnPrepareContext" interface -func (cn *conn) PrepareContext(ctx context.Context, query string) (driver.Stmt, error) { - if finish := cn.watchCancel(ctx); finish != nil { - defer finish() - } - return cn.Prepare(query) -} - -// Implement the "ConnBeginTx" interface -func (cn *conn) BeginTx(ctx context.Context, opts driver.TxOptions) (driver.Tx, error) { - var mode string - - switch sql.IsolationLevel(opts.Isolation) { - case sql.LevelDefault: - // Don't touch mode: use the server's default - case sql.LevelReadUncommitted: - mode = " ISOLATION LEVEL READ UNCOMMITTED" - case sql.LevelReadCommitted: - mode = " ISOLATION LEVEL READ COMMITTED" - case sql.LevelRepeatableRead: - mode = " ISOLATION LEVEL REPEATABLE READ" - case sql.LevelSerializable: - mode = " ISOLATION LEVEL SERIALIZABLE" - default: - return nil, fmt.Errorf("pq: isolation level not supported: %d", opts.Isolation) - } - - if opts.ReadOnly { - mode += " READ ONLY" - } else { - mode += " READ WRITE" - } - - tx, err := cn.begin(mode) - if err != nil { - return nil, err - } - cn.txnFinish = cn.watchCancel(ctx) - return tx, nil -} - -func (cn *conn) Ping(ctx context.Context) error { - if finish := cn.watchCancel(ctx); finish != nil { - defer finish() - } - rows, err := cn.simpleQuery(";") - if err != nil { - return driver.ErrBadConn // https://golang.org/pkg/database/sql/driver/#Pinger - } - rows.Close() - return nil -} - -func (cn *conn) watchCancel(ctx context.Context) func() { - if done := ctx.Done(); done != nil { - finished := make(chan struct{}, 1) - go func() { - select { - case <-done: - select { - case finished <- struct{}{}: - default: - // We raced with the finish func, let the next query handle this with the - // context. - return - } - - // Set the connection state to bad so it does not get reused. - cn.err.set(ctx.Err()) - - // At this point the function level context is canceled, - // so it must not be used for the additional network - // request to cancel the query. - // Create a new context to pass into the dial. - ctxCancel, cancel := context.WithTimeout(context.Background(), watchCancelDialContextTimeout) - defer cancel() - - _ = cn.cancel(ctxCancel) - case <-finished: - } - }() - return func() { - select { - case <-finished: - cn.err.set(ctx.Err()) - cn.Close() - case finished <- struct{}{}: - } - } - } - return nil -} - -func (cn *conn) cancel(ctx context.Context) error { - // Create a new values map (copy). This makes sure the connection created - // in this method cannot write to the same underlying data, which could - // cause a concurrent map write panic. This is necessary because cancel - // is called from a goroutine in watchCancel. - o := make(values) - for k, v := range cn.opts { - o[k] = v - } - - c, err := dial(ctx, cn.dialer, o) - if err != nil { - return err - } - defer c.Close() - - { - can := conn{ - c: c, - } - err = can.ssl(o) - if err != nil { - return err - } - - w := can.writeBuf(0) - w.int32(80877102) // cancel request code - w.int32(cn.processID) - w.int32(cn.secretKey) - - if err := can.sendStartupPacket(w); err != nil { - return err - } - } - - // Read until EOF to ensure that the server received the cancel. - { - _, err := io.Copy(ioutil.Discard, c) - return err - } -} - -// Implement the "StmtQueryContext" interface -func (st *stmt) QueryContext(ctx context.Context, args []driver.NamedValue) (driver.Rows, error) { - list := make([]driver.Value, len(args)) - for i, nv := range args { - list[i] = nv.Value - } - finish := st.watchCancel(ctx) - r, err := st.query(list) - if err != nil { - if finish != nil { - finish() - } - return nil, err - } - r.finish = finish - return r, nil -} - -// Implement the "StmtExecContext" interface -func (st *stmt) ExecContext(ctx context.Context, args []driver.NamedValue) (driver.Result, error) { - list := make([]driver.Value, len(args)) - for i, nv := range args { - list[i] = nv.Value - } - - if finish := st.watchCancel(ctx); finish != nil { - defer finish() - } - - return st.Exec(list) -} - -// watchCancel is implemented on stmt in order to not mark the parent conn as bad -func (st *stmt) watchCancel(ctx context.Context) func() { - if done := ctx.Done(); done != nil { - finished := make(chan struct{}) - go func() { - select { - case <-done: - // At this point the function level context is canceled, - // so it must not be used for the additional network - // request to cancel the query. - // Create a new context to pass into the dial. - ctxCancel, cancel := context.WithTimeout(context.Background(), watchCancelDialContextTimeout) - defer cancel() - - _ = st.cancel(ctxCancel) - finished <- struct{}{} - case <-finished: - } - }() - return func() { - select { - case <-finished: - case finished <- struct{}{}: - } - } - } - return nil -} - -func (st *stmt) cancel(ctx context.Context) error { - return st.cn.cancel(ctx) -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/conn_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/conn_test.go deleted file mode 100644 index b32f983ab..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/conn_test.go +++ /dev/null @@ -1,1967 +0,0 @@ -package pq - -import ( - "context" - "database/sql" - "database/sql/driver" - "fmt" - "io" - "net" - "os" - "reflect" - "strings" - "testing" - "time" -) - -type Fatalistic interface { - Fatal(args ...interface{}) -} - -func forceBinaryParameters() bool { - bp := os.Getenv("PQTEST_BINARY_PARAMETERS") - if bp == "yes" { - return true - } else if bp == "" || bp == "no" { - return false - } else { - panic("unexpected value for PQTEST_BINARY_PARAMETERS") - } -} - -func testConninfo(conninfo string) string { - defaultTo := func(envvar string, value string) { - if os.Getenv(envvar) == "" { - os.Setenv(envvar, value) - } - } - defaultTo("PGDATABASE", "pqgotest") - defaultTo("PGSSLMODE", "disable") - defaultTo("PGCONNECT_TIMEOUT", "20") - - if forceBinaryParameters() && - !strings.HasPrefix(conninfo, "postgres://") && - !strings.HasPrefix(conninfo, "postgresql://") { - conninfo += " binary_parameters=yes" - } - return conninfo -} - -func openTestConnConninfo(conninfo string) (*sql.DB, error) { - return sql.Open("postgres", testConninfo(conninfo)) -} - -func openTestConn(t Fatalistic) *sql.DB { - conn, err := openTestConnConninfo("") - if err != nil { - t.Fatal(err) - } - - return conn -} - -func getServerVersion(t *testing.T, db *sql.DB) int { - var version int - err := db.QueryRow("SHOW server_version_num").Scan(&version) - if err != nil { - t.Fatal(err) - } - return version -} - -func TestReconnect(t *testing.T) { - db1 := openTestConn(t) - defer db1.Close() - tx, err := db1.Begin() - if err != nil { - t.Fatal(err) - } - var pid1 int - err = tx.QueryRow("SELECT pg_backend_pid()").Scan(&pid1) - if err != nil { - t.Fatal(err) - } - db2 := openTestConn(t) - defer db2.Close() - _, err = db2.Exec("SELECT pg_terminate_backend($1)", pid1) - if err != nil { - t.Fatal(err) - } - // The rollback will probably "fail" because we just killed - // its connection above - _ = tx.Rollback() - - const expected int = 42 - var result int - err = db1.QueryRow(fmt.Sprintf("SELECT %d", expected)).Scan(&result) - if err != nil { - t.Fatal(err) - } - if result != expected { - t.Errorf("got %v; expected %v", result, expected) - } -} - -func TestCommitInFailedTransaction(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - rows, err := txn.Query("SELECT error") - if err == nil { - rows.Close() - t.Fatal("expected failure") - } - err = txn.Commit() - if err != ErrInFailedTransaction { - t.Fatalf("expected ErrInFailedTransaction; got %#v", err) - } -} - -func TestOpenURL(t *testing.T) { - testURL := func(url string) { - db, err := openTestConnConninfo(url) - if err != nil { - t.Fatal(err) - } - defer db.Close() - // database/sql might not call our Open at all unless we do something with - // the connection - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - txn.Rollback() - } - testURL("postgres://") - testURL("postgresql://") -} - -const pgpassFile = "/tmp/pqgotest_pgpass" - -func TestPgpass(t *testing.T) { - if os.Getenv("TRAVIS") != "true" { - t.Skip("not running under Travis, skipping pgpass tests") - } - - testAssert := func(conninfo string, expected string, reason string) { - conn, err := openTestConnConninfo(conninfo) - if err != nil { - t.Fatal(err) - } - defer conn.Close() - - txn, err := conn.Begin() - if err != nil { - if expected != "fail" { - t.Fatalf(reason, err) - } - return - } - rows, err := txn.Query("SELECT USER") - if err != nil { - txn.Rollback() - if expected != "fail" { - t.Fatalf(reason, err) - } - } else { - rows.Close() - if expected != "ok" { - t.Fatalf(reason, err) - } - } - txn.Rollback() - } - testAssert("", "ok", "missing .pgpass, unexpected error %#v") - os.Setenv("PGPASSFILE", pgpassFile) - testAssert("host=/tmp", "fail", ", unexpected error %#v") - os.Remove(pgpassFile) - pgpass, err := os.OpenFile(pgpassFile, os.O_RDWR|os.O_CREATE, 0644) - if err != nil { - t.Fatalf("Unexpected error writing pgpass file %#v", err) - } - _, err = pgpass.WriteString(`# comment -server:5432:some_db:some_user:pass_A -*:5432:some_db:some_user:pass_B -localhost:*:*:*:pass_C -*:*:*:*:pass_fallback -`) - if err != nil { - t.Fatalf("Unexpected error writing pgpass file %#v", err) - } - pgpass.Close() - - assertPassword := func(extra values, expected string) { - o := values{ - "host": "localhost", - "sslmode": "disable", - "connect_timeout": "20", - "user": "majid", - "port": "5432", - "extra_float_digits": "2", - "dbname": "pqgotest", - "client_encoding": "UTF8", - "datestyle": "ISO, MDY", - } - for k, v := range extra { - o[k] = v - } - (&conn{}).handlePgpass(o) - if pw := o["password"]; pw != expected { - t.Fatalf("For %v expected %s got %s", extra, expected, pw) - } - } - // wrong permissions for the pgpass file means it should be ignored - assertPassword(values{"host": "example.com", "user": "foo"}, "") - // fix the permissions and check if it has taken effect - os.Chmod(pgpassFile, 0600) - assertPassword(values{"host": "server", "dbname": "some_db", "user": "some_user"}, "pass_A") - assertPassword(values{"host": "example.com", "user": "foo"}, "pass_fallback") - assertPassword(values{"host": "example.com", "dbname": "some_db", "user": "some_user"}, "pass_B") - // localhost also matches the default "" and UNIX sockets - assertPassword(values{"host": "", "user": "some_user"}, "pass_C") - assertPassword(values{"host": "/tmp", "user": "some_user"}, "pass_C") - // cleanup - os.Remove(pgpassFile) - os.Setenv("PGPASSFILE", "") -} - -func TestExec(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - _, err := db.Exec("CREATE TEMP TABLE temp (a int)") - if err != nil { - t.Fatal(err) - } - - r, err := db.Exec("INSERT INTO temp VALUES (1)") - if err != nil { - t.Fatal(err) - } - - if n, _ := r.RowsAffected(); n != 1 { - t.Fatalf("expected 1 row affected, not %d", n) - } - - r, err = db.Exec("INSERT INTO temp VALUES ($1), ($2), ($3)", 1, 2, 3) - if err != nil { - t.Fatal(err) - } - - if n, _ := r.RowsAffected(); n != 3 { - t.Fatalf("expected 3 rows affected, not %d", n) - } - - // SELECT doesn't send the number of returned rows in the command tag - // before 9.0 - if getServerVersion(t, db) >= 90000 { - r, err = db.Exec("SELECT g FROM generate_series(1, 2) g") - if err != nil { - t.Fatal(err) - } - if n, _ := r.RowsAffected(); n != 2 { - t.Fatalf("expected 2 rows affected, not %d", n) - } - - r, err = db.Exec("SELECT g FROM generate_series(1, $1) g", 3) - if err != nil { - t.Fatal(err) - } - if n, _ := r.RowsAffected(); n != 3 { - t.Fatalf("expected 3 rows affected, not %d", n) - } - } -} - -func TestStatment(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - st, err := db.Prepare("SELECT 1") - if err != nil { - t.Fatal(err) - } - - st1, err := db.Prepare("SELECT 2") - if err != nil { - t.Fatal(err) - } - - r, err := st.Query() - if err != nil { - t.Fatal(err) - } - defer r.Close() - - if !r.Next() { - t.Fatal("expected row") - } - - var i int - err = r.Scan(&i) - if err != nil { - t.Fatal(err) - } - - if i != 1 { - t.Fatalf("expected 1, got %d", i) - } - - // st1 - - r1, err := st1.Query() - if err != nil { - t.Fatal(err) - } - defer r1.Close() - - if !r1.Next() { - if r.Err() != nil { - t.Fatal(r1.Err()) - } - t.Fatal("expected row") - } - - err = r1.Scan(&i) - if err != nil { - t.Fatal(err) - } - - if i != 2 { - t.Fatalf("expected 2, got %d", i) - } -} - -func TestRowsCloseBeforeDone(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - r, err := db.Query("SELECT 1") - if err != nil { - t.Fatal(err) - } - - err = r.Close() - if err != nil { - t.Fatal(err) - } - - if r.Next() { - t.Fatal("unexpected row") - } - - if r.Err() != nil { - t.Fatal(r.Err()) - } -} - -func TestParameterCountMismatch(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - var notused int - err := db.QueryRow("SELECT false", 1).Scan(¬used) - if err == nil { - t.Fatal("expected err") - } - // make sure we clean up correctly - err = db.QueryRow("SELECT 1").Scan(¬used) - if err != nil { - t.Fatal(err) - } - - err = db.QueryRow("SELECT $1").Scan(¬used) - if err == nil { - t.Fatal("expected err") - } - // make sure we clean up correctly - err = db.QueryRow("SELECT 1").Scan(¬used) - if err != nil { - t.Fatal(err) - } -} - -// Test that EmptyQueryResponses are handled correctly. -func TestEmptyQuery(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - res, err := db.Exec("") - if err != nil { - t.Fatal(err) - } - if _, err := res.RowsAffected(); err != errNoRowsAffected { - t.Fatalf("expected %s, got %v", errNoRowsAffected, err) - } - if _, err := res.LastInsertId(); err != errNoLastInsertID { - t.Fatalf("expected %s, got %v", errNoLastInsertID, err) - } - rows, err := db.Query("") - if err != nil { - t.Fatal(err) - } - cols, err := rows.Columns() - if err != nil { - t.Fatal(err) - } - if len(cols) != 0 { - t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols)) - } - if rows.Next() { - t.Fatal("unexpected row") - } - if rows.Err() != nil { - t.Fatal(rows.Err()) - } - - stmt, err := db.Prepare("") - if err != nil { - t.Fatal(err) - } - res, err = stmt.Exec() - if err != nil { - t.Fatal(err) - } - if _, err := res.RowsAffected(); err != errNoRowsAffected { - t.Fatalf("expected %s, got %v", errNoRowsAffected, err) - } - if _, err := res.LastInsertId(); err != errNoLastInsertID { - t.Fatalf("expected %s, got %v", errNoLastInsertID, err) - } - rows, err = stmt.Query() - if err != nil { - t.Fatal(err) - } - cols, err = rows.Columns() - if err != nil { - t.Fatal(err) - } - if len(cols) != 0 { - t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols)) - } - if rows.Next() { - t.Fatal("unexpected row") - } - if rows.Err() != nil { - t.Fatal(rows.Err()) - } -} - -// Test that rows.Columns() is correct even if there are no result rows. -func TestEmptyResultSetColumns(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - rows, err := db.Query("SELECT 1 AS a, text 'bar' AS bar WHERE FALSE") - if err != nil { - t.Fatal(err) - } - cols, err := rows.Columns() - if err != nil { - t.Fatal(err) - } - if len(cols) != 2 { - t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols)) - } - if rows.Next() { - t.Fatal("unexpected row") - } - if rows.Err() != nil { - t.Fatal(rows.Err()) - } - if cols[0] != "a" || cols[1] != "bar" { - t.Fatalf("unexpected Columns result %v", cols) - } - - stmt, err := db.Prepare("SELECT $1::int AS a, text 'bar' AS bar WHERE FALSE") - if err != nil { - t.Fatal(err) - } - rows, err = stmt.Query(1) - if err != nil { - t.Fatal(err) - } - cols, err = rows.Columns() - if err != nil { - t.Fatal(err) - } - if len(cols) != 2 { - t.Fatalf("unexpected number of columns %d in response to an empty query", len(cols)) - } - if rows.Next() { - t.Fatal("unexpected row") - } - if rows.Err() != nil { - t.Fatal(rows.Err()) - } - if cols[0] != "a" || cols[1] != "bar" { - t.Fatalf("unexpected Columns result %v", cols) - } - -} - -func TestEncodeDecode(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - q := ` - SELECT - E'\\000\\001\\002'::bytea, - 'foobar'::text, - NULL::integer, - '2000-1-1 01:02:03.04-7'::timestamptz, - 0::boolean, - 123, - -321, - 3.14::float8 - WHERE - E'\\000\\001\\002'::bytea = $1 - AND 'foobar'::text = $2 - AND $3::integer is NULL - ` - // AND '2000-1-1 12:00:00.000000-7'::timestamp = $3 - - exp1 := []byte{0, 1, 2} - exp2 := "foobar" - - r, err := db.Query(q, exp1, exp2, nil) - if err != nil { - t.Fatal(err) - } - defer r.Close() - - if !r.Next() { - if r.Err() != nil { - t.Fatal(r.Err()) - } - t.Fatal("expected row") - } - - var got1 []byte - var got2 string - var got3 = sql.NullInt64{Valid: true} - var got4 time.Time - var got5, got6, got7, got8 interface{} - - err = r.Scan(&got1, &got2, &got3, &got4, &got5, &got6, &got7, &got8) - if err != nil { - t.Fatal(err) - } - - if !reflect.DeepEqual(exp1, got1) { - t.Errorf("expected %q byte: %q", exp1, got1) - } - - if !reflect.DeepEqual(exp2, got2) { - t.Errorf("expected %q byte: %q", exp2, got2) - } - - if got3.Valid { - t.Fatal("expected invalid") - } - - if got4.Year() != 2000 { - t.Fatal("wrong year") - } - - if got5 != false { - t.Fatalf("expected false, got %q", got5) - } - - if got6 != int64(123) { - t.Fatalf("expected 123, got %d", got6) - } - - if got7 != int64(-321) { - t.Fatalf("expected -321, got %d", got7) - } - - if got8 != float64(3.14) { - t.Fatalf("expected 3.14, got %f", got8) - } -} - -func TestNoData(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - st, err := db.Prepare("SELECT 1 WHERE true = false") - if err != nil { - t.Fatal(err) - } - defer st.Close() - - r, err := st.Query() - if err != nil { - t.Fatal(err) - } - defer r.Close() - - if r.Next() { - if r.Err() != nil { - t.Fatal(r.Err()) - } - t.Fatal("unexpected row") - } - - _, err = db.Query("SELECT * FROM nonexistenttable WHERE age=$1", 20) - if err == nil { - t.Fatal("Should have raised an error on non existent table") - } - - _, err = db.Query("SELECT * FROM nonexistenttable") - if err == nil { - t.Fatal("Should have raised an error on non existent table") - } -} - -func TestErrorDuringStartup(t *testing.T) { - // Don't use the normal connection setup, this is intended to - // blow up in the startup packet from a non-existent user. - db, err := openTestConnConninfo("user=thisuserreallydoesntexist") - if err != nil { - t.Fatal(err) - } - defer db.Close() - - _, err = db.Begin() - if err == nil { - t.Fatal("expected error") - } - - e, ok := err.(*Error) - if !ok { - t.Fatalf("expected Error, got %#v", err) - } else if e.Code.Name() != "invalid_authorization_specification" && e.Code.Name() != "invalid_password" { - t.Fatalf("expected invalid_authorization_specification or invalid_password, got %s (%+v)", e.Code.Name(), err) - } -} - -type testConn struct { - closed bool - net.Conn -} - -func (c *testConn) Close() error { - c.closed = true - return c.Conn.Close() -} - -type testDialer struct { - conns []*testConn -} - -func (d *testDialer) Dial(ntw, addr string) (net.Conn, error) { - c, err := net.Dial(ntw, addr) - if err != nil { - return nil, err - } - tc := &testConn{Conn: c} - d.conns = append(d.conns, tc) - return tc, nil -} - -func (d *testDialer) DialTimeout(ntw, addr string, timeout time.Duration) (net.Conn, error) { - c, err := net.DialTimeout(ntw, addr, timeout) - if err != nil { - return nil, err - } - tc := &testConn{Conn: c} - d.conns = append(d.conns, tc) - return tc, nil -} - -func TestErrorDuringStartupClosesConn(t *testing.T) { - // Don't use the normal connection setup, this is intended to - // blow up in the startup packet from a non-existent user. - var d testDialer - c, err := DialOpen(&d, testConninfo("user=thisuserreallydoesntexist")) - if err == nil { - c.Close() - t.Fatal("expected dial error") - } - if len(d.conns) != 1 { - t.Fatalf("got len(d.conns) = %d, want = %d", len(d.conns), 1) - } - if !d.conns[0].closed { - t.Error("connection leaked") - } -} - -func TestBadConn(t *testing.T) { - var err error - - cn := conn{} - func() { - defer cn.errRecover(&err) - panic(io.EOF) - }() - if err != driver.ErrBadConn { - t.Fatalf("expected driver.ErrBadConn, got: %#v", err) - } - if err := cn.err.get(); err != driver.ErrBadConn { - t.Fatalf("expected driver.ErrBadConn, got %#v", err) - } - - cn = conn{} - func() { - defer cn.errRecover(&err) - e := &Error{Severity: Efatal} - panic(e) - }() - if err != driver.ErrBadConn { - t.Fatalf("expected driver.ErrBadConn, got: %#v", err) - } - if err := cn.err.get(); err != driver.ErrBadConn { - t.Fatalf("expected driver.ErrBadConn, got %#v", err) - } -} - -// TestCloseBadConn tests that the underlying connection can be closed with -// Close after an error. -func TestCloseBadConn(t *testing.T) { - host := os.Getenv("PGHOST") - if host == "" { - host = "localhost" - } - port := os.Getenv("PGPORT") - if port == "" { - port = "5432" - } - nc, err := net.Dial("tcp", host+":"+port) - if err != nil { - t.Fatal(err) - } - cn := conn{c: nc} - func() { - defer cn.errRecover(&err) - panic(io.EOF) - }() - // Verify we can write before closing. - if _, err := nc.Write(nil); err != nil { - t.Fatal(err) - } - // First close should close the connection. - if err := cn.Close(); err != nil { - t.Fatal(err) - } - - // During the Go 1.9 cycle, https://github.com/golang/go/commit/3792db5 - // changed this error from - // - // net.errClosing = errors.New("use of closed network connection") - // - // to - // - // internal/poll.ErrClosing = errors.New("use of closed file or network connection") - const errClosing = "use of closed" - - // Verify write after closing fails. - if _, err := nc.Write(nil); err == nil { - t.Fatal("expected error") - } else if !strings.Contains(err.Error(), errClosing) { - t.Fatalf("expected %s error, got %s", errClosing, err) - } - // Verify second close fails. - if err := cn.Close(); err == nil { - t.Fatal("expected error") - } else if !strings.Contains(err.Error(), errClosing) { - t.Fatalf("expected %s error, got %s", errClosing, err) - } -} - -func TestErrorOnExec(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)") - if err != nil { - t.Fatal(err) - } - - _, err = txn.Exec("INSERT INTO foo VALUES (0), (0)") - if err == nil { - t.Fatal("Should have raised error") - } - - e, ok := err.(*Error) - if !ok { - t.Fatalf("expected Error, got %#v", err) - } else if e.Code.Name() != "unique_violation" { - t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err) - } -} - -func TestErrorOnQuery(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)") - if err != nil { - t.Fatal(err) - } - - _, err = txn.Query("INSERT INTO foo VALUES (0), (0)") - if err == nil { - t.Fatal("Should have raised error") - } - - e, ok := err.(*Error) - if !ok { - t.Fatalf("expected Error, got %#v", err) - } else if e.Code.Name() != "unique_violation" { - t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err) - } -} - -func TestErrorOnQueryRowSimpleQuery(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMPORARY TABLE foo(f1 int PRIMARY KEY)") - if err != nil { - t.Fatal(err) - } - - var v int - err = txn.QueryRow("INSERT INTO foo VALUES (0), (0)").Scan(&v) - if err == nil { - t.Fatal("Should have raised error") - } - - e, ok := err.(*Error) - if !ok { - t.Fatalf("expected Error, got %#v", err) - } else if e.Code.Name() != "unique_violation" { - t.Fatalf("expected unique_violation, got %s (%+v)", e.Code.Name(), err) - } -} - -// Test the QueryRow bug workarounds in stmt.exec() and simpleQuery() -func TestQueryRowBugWorkaround(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - // stmt.exec() - _, err := db.Exec("CREATE TEMP TABLE notnulltemp (a varchar(10) not null)") - if err != nil { - t.Fatal(err) - } - - var a string - err = db.QueryRow("INSERT INTO notnulltemp(a) values($1) RETURNING a", nil).Scan(&a) - if err == sql.ErrNoRows { - t.Fatalf("expected constraint violation error; got: %v", err) - } - pge, ok := err.(*Error) - if !ok { - t.Fatalf("expected *Error; got: %#v", err) - } - if pge.Code.Name() != "not_null_violation" { - t.Fatalf("expected not_null_violation; got: %s (%+v)", pge.Code.Name(), err) - } - - // Test workaround in simpleQuery() - tx, err := db.Begin() - if err != nil { - t.Fatalf("unexpected error %s in Begin", err) - } - defer tx.Rollback() - - _, err = tx.Exec("SET LOCAL check_function_bodies TO FALSE") - if err != nil { - t.Fatalf("could not disable check_function_bodies: %s", err) - } - _, err = tx.Exec(` -CREATE OR REPLACE FUNCTION bad_function() -RETURNS integer --- hack to prevent the function from being inlined -SET check_function_bodies TO TRUE -AS $$ - SELECT text 'bad' -$$ LANGUAGE sql`) - if err != nil { - t.Fatalf("could not create function: %s", err) - } - - err = tx.QueryRow("SELECT * FROM bad_function()").Scan(&a) - if err == nil { - t.Fatalf("expected error") - } - pge, ok = err.(*Error) - if !ok { - t.Fatalf("expected *Error; got: %#v", err) - } - if pge.Code.Name() != "invalid_function_definition" { - t.Fatalf("expected invalid_function_definition; got: %s (%+v)", pge.Code.Name(), err) - } - - err = tx.Rollback() - if err != nil { - t.Fatalf("unexpected error %s in Rollback", err) - } - - // Also test that simpleQuery()'s workaround works when the query fails - // after a row has been received. - rows, err := db.Query(` -select - (select generate_series(1, ss.i)) -from (select gs.i - from generate_series(1, 2) gs(i) - order by gs.i limit 2) ss`) - if err != nil { - t.Fatalf("query failed: %s", err) - } - if !rows.Next() { - t.Fatalf("expected at least one result row; got %s", rows.Err()) - } - var i int - err = rows.Scan(&i) - if err != nil { - t.Fatalf("rows.Scan() failed: %s", err) - } - if i != 1 { - t.Fatalf("unexpected value for i: %d", i) - } - if rows.Next() { - t.Fatalf("unexpected row") - } - pge, ok = rows.Err().(*Error) - if !ok { - t.Fatalf("expected *Error; got: %#v", err) - } - if pge.Code.Name() != "cardinality_violation" { - t.Fatalf("expected cardinality_violation; got: %s (%+v)", pge.Code.Name(), rows.Err()) - } -} - -func TestSimpleQuery(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - r, err := db.Query("select 1") - if err != nil { - t.Fatal(err) - } - defer r.Close() - - if !r.Next() { - t.Fatal("expected row") - } -} - -func TestBindError(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - _, err := db.Exec("create temp table test (i integer)") - if err != nil { - t.Fatal(err) - } - - _, err = db.Query("select * from test where i=$1", "hhh") - if err == nil { - t.Fatal("expected an error") - } - - // Should not get error here - r, err := db.Query("select * from test where i=$1", 1) - if err != nil { - t.Fatal(err) - } - defer r.Close() -} - -func TestParseErrorInExtendedQuery(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - _, err := db.Query("PARSE_ERROR $1", 1) - pqErr, _ := err.(*Error) - // Expecting a syntax error. - if err == nil || pqErr == nil || pqErr.Code != "42601" { - t.Fatalf("expected syntax error, got %s", err) - } - - rows, err := db.Query("SELECT 1") - if err != nil { - t.Fatal(err) - } - rows.Close() -} - -// TestReturning tests that an INSERT query using the RETURNING clause returns a row. -func TestReturning(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - _, err := db.Exec("CREATE TEMP TABLE distributors (did integer default 0, dname text)") - if err != nil { - t.Fatal(err) - } - - rows, err := db.Query("INSERT INTO distributors (did, dname) VALUES (DEFAULT, 'XYZ Widgets') " + - "RETURNING did;") - if err != nil { - t.Fatal(err) - } - if !rows.Next() { - t.Fatal("no rows") - } - var did int - err = rows.Scan(&did) - if err != nil { - t.Fatal(err) - } - if did != 0 { - t.Fatalf("bad value for did: got %d, want %d", did, 0) - } - - if rows.Next() { - t.Fatal("unexpected next row") - } - err = rows.Err() - if err != nil { - t.Fatal(err) - } -} - -func TestIssue186(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - // Exec() a query which returns results - _, err := db.Exec("VALUES (1), (2), (3)") - if err != nil { - t.Fatal(err) - } - - _, err = db.Exec("VALUES ($1), ($2), ($3)", 1, 2, 3) - if err != nil { - t.Fatal(err) - } - - // Query() a query which doesn't return any results - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - rows, err := txn.Query("CREATE TEMP TABLE foo(f1 int)") - if err != nil { - t.Fatal(err) - } - if err = rows.Close(); err != nil { - t.Fatal(err) - } - - // small trick to get NoData from a parameterized query - _, err = txn.Exec("CREATE RULE nodata AS ON INSERT TO foo DO INSTEAD NOTHING") - if err != nil { - t.Fatal(err) - } - rows, err = txn.Query("INSERT INTO foo VALUES ($1)", 1) - if err != nil { - t.Fatal(err) - } - if err = rows.Close(); err != nil { - t.Fatal(err) - } -} - -func TestIssue196(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - row := db.QueryRow("SELECT float4 '0.10000122' = $1, float8 '35.03554004971999' = $2", - float32(0.10000122), float64(35.03554004971999)) - - var float4match, float8match bool - err := row.Scan(&float4match, &float8match) - if err != nil { - t.Fatal(err) - } - if !float4match { - t.Errorf("Expected float4 fidelity to be maintained; got no match") - } - if !float8match { - t.Errorf("Expected float8 fidelity to be maintained; got no match") - } -} - -// Test that any CommandComplete messages sent before the query results are -// ignored. -func TestIssue282(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - var searchPath string - err := db.QueryRow(` - SET LOCAL search_path TO pg_catalog; - SET LOCAL search_path TO pg_catalog; - SHOW search_path`).Scan(&searchPath) - if err != nil { - t.Fatal(err) - } - if searchPath != "pg_catalog" { - t.Fatalf("unexpected search_path %s", searchPath) - } -} - -func TestReadFloatPrecision(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - row := db.QueryRow("SELECT float4 '0.10000122', float8 '35.03554004971999', float4 '1.2'") - var float4val float32 - var float8val float64 - var float4val2 float64 - err := row.Scan(&float4val, &float8val, &float4val2) - if err != nil { - t.Fatal(err) - } - if float4val != float32(0.10000122) { - t.Errorf("Expected float4 fidelity to be maintained; got no match") - } - if float8val != float64(35.03554004971999) { - t.Errorf("Expected float8 fidelity to be maintained; got no match") - } - if float4val2 != float64(1.2) { - t.Errorf("Expected float4 fidelity into a float64 to be maintained; got no match") - } -} - -func TestXactMultiStmt(t *testing.T) { - // minified test case based on bug reports from - // pico303@gmail.com and rangelspam@gmail.com - t.Skip("Skipping failing test") - db := openTestConn(t) - defer db.Close() - - tx, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer tx.Commit() - - rows, err := tx.Query("select 1") - if err != nil { - t.Fatal(err) - } - - if rows.Next() { - var val int32 - if err = rows.Scan(&val); err != nil { - t.Fatal(err) - } - } else { - t.Fatal("Expected at least one row in first query in xact") - } - - rows2, err := tx.Query("select 2") - if err != nil { - t.Fatal(err) - } - - if rows2.Next() { - var val2 int32 - if err := rows2.Scan(&val2); err != nil { - t.Fatal(err) - } - } else { - t.Fatal("Expected at least one row in second query in xact") - } - - if err = rows.Err(); err != nil { - t.Fatal(err) - } - - if err = rows2.Err(); err != nil { - t.Fatal(err) - } - - if err = tx.Commit(); err != nil { - t.Fatal(err) - } -} - -var envParseTests = []struct { - Expected map[string]string - Env []string -}{ - { - Env: []string{"PGDATABASE=hello", "PGUSER=goodbye"}, - Expected: map[string]string{"dbname": "hello", "user": "goodbye"}, - }, - { - Env: []string{"PGDATESTYLE=ISO, MDY"}, - Expected: map[string]string{"datestyle": "ISO, MDY"}, - }, - { - Env: []string{"PGCONNECT_TIMEOUT=30"}, - Expected: map[string]string{"connect_timeout": "30"}, - }, -} - -func TestParseEnviron(t *testing.T) { - for i, tt := range envParseTests { - results := parseEnviron(tt.Env) - if !reflect.DeepEqual(tt.Expected, results) { - t.Errorf("%d: Expected: %#v Got: %#v", i, tt.Expected, results) - } - } -} - -func TestParseComplete(t *testing.T) { - tpc := func(commandTag string, command string, affectedRows int64, shouldFail bool) { - defer func() { - if p := recover(); p != nil { - if !shouldFail { - t.Error(p) - } - } - }() - cn := &conn{} - res, c := cn.parseComplete(commandTag) - if c != command { - t.Errorf("Expected %v, got %v", command, c) - } - n, err := res.RowsAffected() - if err != nil { - t.Fatal(err) - } - if n != affectedRows { - t.Errorf("Expected %d, got %d", affectedRows, n) - } - } - - tpc("ALTER TABLE", "ALTER TABLE", 0, false) - tpc("INSERT 0 1", "INSERT", 1, false) - tpc("UPDATE 100", "UPDATE", 100, false) - tpc("SELECT 100", "SELECT", 100, false) - tpc("FETCH 100", "FETCH", 100, false) - // allow COPY (and others) without row count - tpc("COPY", "COPY", 0, false) - // don't fail on command tags we don't recognize - tpc("UNKNOWNCOMMANDTAG", "UNKNOWNCOMMANDTAG", 0, false) - - // failure cases - tpc("INSERT 1", "", 0, true) // missing oid - tpc("UPDATE 0 1", "", 0, true) // too many numbers - tpc("SELECT foo", "", 0, true) // invalid row count -} - -// Test interface conformance. -var ( - _ driver.ExecerContext = (*conn)(nil) - _ driver.QueryerContext = (*conn)(nil) -) - -func TestNullAfterNonNull(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - r, err := db.Query("SELECT 9::integer UNION SELECT NULL::integer") - if err != nil { - t.Fatal(err) - } - - var n sql.NullInt64 - - if !r.Next() { - if r.Err() != nil { - t.Fatal(err) - } - t.Fatal("expected row") - } - - if err := r.Scan(&n); err != nil { - t.Fatal(err) - } - - if n.Int64 != 9 { - t.Fatalf("expected 2, not %d", n.Int64) - } - - if !r.Next() { - if r.Err() != nil { - t.Fatal(err) - } - t.Fatal("expected row") - } - - if err := r.Scan(&n); err != nil { - t.Fatal(err) - } - - if n.Valid { - t.Fatal("expected n to be invalid") - } - - if n.Int64 != 0 { - t.Fatalf("expected n to 2, not %d", n.Int64) - } -} - -func Test64BitErrorChecking(t *testing.T) { - defer func() { - if err := recover(); err != nil { - t.Fatal("panic due to 0xFFFFFFFF != -1 " + - "when int is 64 bits") - } - }() - - db := openTestConn(t) - defer db.Close() - - r, err := db.Query(`SELECT * -FROM (VALUES (0::integer, NULL::text), (1, 'test string')) AS t;`) - - if err != nil { - t.Fatal(err) - } - - defer r.Close() - - for r.Next() { - } -} - -func TestCommit(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - _, err := db.Exec("CREATE TEMP TABLE temp (a int)") - if err != nil { - t.Fatal(err) - } - sqlInsert := "INSERT INTO temp VALUES (1)" - sqlSelect := "SELECT * FROM temp" - tx, err := db.Begin() - if err != nil { - t.Fatal(err) - } - _, err = tx.Exec(sqlInsert) - if err != nil { - t.Fatal(err) - } - err = tx.Commit() - if err != nil { - t.Fatal(err) - } - var i int - err = db.QueryRow(sqlSelect).Scan(&i) - if err != nil { - t.Fatal(err) - } - if i != 1 { - t.Fatalf("expected 1, got %d", i) - } -} - -func TestErrorClass(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - _, err := db.Query("SELECT int 'notint'") - if err == nil { - t.Fatal("expected error") - } - pge, ok := err.(*Error) - if !ok { - t.Fatalf("expected *pq.Error, got %#+v", err) - } - if pge.Code.Class() != "22" { - t.Fatalf("expected class 28, got %v", pge.Code.Class()) - } - if pge.Code.Class().Name() != "data_exception" { - t.Fatalf("expected data_exception, got %v", pge.Code.Class().Name()) - } -} - -func TestParseOpts(t *testing.T) { - tests := []struct { - in string - expected values - valid bool - }{ - {"dbname=hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true}, - {"dbname=hello user=goodbye ", values{"dbname": "hello", "user": "goodbye"}, true}, - {"dbname = hello user=goodbye", values{"dbname": "hello", "user": "goodbye"}, true}, - {"dbname=hello user =goodbye", values{"dbname": "hello", "user": "goodbye"}, true}, - {"dbname=hello user= goodbye", values{"dbname": "hello", "user": "goodbye"}, true}, - {"host=localhost password='correct horse battery staple'", values{"host": "localhost", "password": "correct horse battery staple"}, true}, - {"dbname=データベース password=パスワード", values{"dbname": "データベース", "password": "パスワード"}, true}, - {"dbname=hello user=''", values{"dbname": "hello", "user": ""}, true}, - {"user='' dbname=hello", values{"dbname": "hello", "user": ""}, true}, - // The last option value is an empty string if there's no non-whitespace after its = - {"dbname=hello user= ", values{"dbname": "hello", "user": ""}, true}, - - // The parser ignores spaces after = and interprets the next set of non-whitespace characters as the value. - {"user= password=foo", values{"user": "password=foo"}, true}, - - // Backslash escapes next char - {`user=a\ \'\\b`, values{"user": `a '\b`}, true}, - {`user='a \'b'`, values{"user": `a 'b`}, true}, - - // Incomplete escape - {`user=x\`, values{}, false}, - - // No '=' after the key - {"postgre://marko@internet", values{}, false}, - {"dbname user=goodbye", values{}, false}, - {"user=foo blah", values{}, false}, - {"user=foo blah ", values{}, false}, - - // Unterminated quoted value - {"dbname=hello user='unterminated", values{}, false}, - } - - for _, test := range tests { - o := make(values) - err := parseOpts(test.in, o) - - switch { - case err != nil && test.valid: - t.Errorf("%q got unexpected error: %s", test.in, err) - case err == nil && test.valid && !reflect.DeepEqual(test.expected, o): - t.Errorf("%q got: %#v want: %#v", test.in, o, test.expected) - case err == nil && !test.valid: - t.Errorf("%q expected an error", test.in) - } - } -} - -func TestRuntimeParameters(t *testing.T) { - tests := []struct { - conninfo string - param string - expected string - success bool - }{ - // invalid parameter - {"DOESNOTEXIST=foo", "", "", false}, - // we can only work with a specific value for these two - {"client_encoding=SQL_ASCII", "", "", false}, - {"datestyle='ISO, YDM'", "", "", false}, - // "options" should work exactly as it does in libpq - {"options='-c search_path=pqgotest'", "search_path", "pqgotest", true}, - // pq should override client_encoding in this case - {"options='-c client_encoding=SQL_ASCII'", "client_encoding", "UTF8", true}, - // allow client_encoding to be set explicitly - {"client_encoding=UTF8", "client_encoding", "UTF8", true}, - // test a runtime parameter not supported by libpq - {"work_mem='139kB'", "work_mem", "139kB", true}, - // test fallback_application_name - {"application_name=foo fallback_application_name=bar", "application_name", "foo", true}, - {"application_name='' fallback_application_name=bar", "application_name", "", true}, - {"fallback_application_name=bar", "application_name", "bar", true}, - } - - for _, test := range tests { - db, err := openTestConnConninfo(test.conninfo) - if err != nil { - t.Fatal(err) - } - - // application_name didn't exist before 9.0 - if test.param == "application_name" && getServerVersion(t, db) < 90000 { - db.Close() - continue - } - - tryGetParameterValue := func() (value string, success bool) { - defer db.Close() - row := db.QueryRow("SELECT current_setting($1)", test.param) - err = row.Scan(&value) - if err != nil { - return "", false - } - return value, true - } - - value, success := tryGetParameterValue() - if success != test.success && !test.success { - t.Fatalf("%v: unexpected error: %v", test.conninfo, err) - } - if success != test.success { - t.Fatalf("unexpected outcome %v (was expecting %v) for conninfo \"%s\"", - success, test.success, test.conninfo) - } - if value != test.expected { - t.Fatalf("bad value for %s: got %s, want %s with conninfo \"%s\"", - test.param, value, test.expected, test.conninfo) - } - } -} - -func TestIsUTF8(t *testing.T) { - var cases = []struct { - name string - want bool - }{ - {"unicode", true}, - {"utf-8", true}, - {"utf_8", true}, - {"UTF-8", true}, - {"UTF8", true}, - {"utf8", true}, - {"u n ic_ode", true}, - {"ut_f%8", true}, - {"ubf8", false}, - {"punycode", false}, - } - - for _, test := range cases { - if g := isUTF8(test.name); g != test.want { - t.Errorf("isUTF8(%q) = %v want %v", test.name, g, test.want) - } - } -} - -func TestQuoteIdentifier(t *testing.T) { - var cases = []struct { - input string - want string - }{ - {`foo`, `"foo"`}, - {`foo bar baz`, `"foo bar baz"`}, - {`foo"bar`, `"foo""bar"`}, - {"foo\x00bar", `"foo"`}, - {"\x00foo", `""`}, - } - - for _, test := range cases { - got := QuoteIdentifier(test.input) - if got != test.want { - t.Errorf("QuoteIdentifier(%q) = %v want %v", test.input, got, test.want) - } - } -} - -func TestQuoteLiteral(t *testing.T) { - var cases = []struct { - input string - want string - }{ - {`foo`, `'foo'`}, - {`foo bar baz`, `'foo bar baz'`}, - {`foo'bar`, `'foo''bar'`}, - {`foo\bar`, ` E'foo\\bar'`}, - {`foo\ba'r`, ` E'foo\\ba''r'`}, - {`foo"bar`, `'foo"bar'`}, - {`foo\x00bar`, ` E'foo\\x00bar'`}, - {`\x00foo`, ` E'\\x00foo'`}, - {`'`, `''''`}, - {`''`, `''''''`}, - {`\`, ` E'\\'`}, - {`'abc'; DROP TABLE users;`, `'''abc''; DROP TABLE users;'`}, - {`\'`, ` E'\\'''`}, - {`E'\''`, ` E'E''\\'''''`}, - {`e'\''`, ` E'e''\\'''''`}, - {`E'\'abc\'; DROP TABLE users;'`, ` E'E''\\''abc\\''; DROP TABLE users;'''`}, - {`e'\'abc\'; DROP TABLE users;'`, ` E'e''\\''abc\\''; DROP TABLE users;'''`}, - } - - for _, test := range cases { - got := QuoteLiteral(test.input) - if got != test.want { - t.Errorf("QuoteLiteral(%q) = %v want %v", test.input, got, test.want) - } - } -} - -func TestRowsResultTag(t *testing.T) { - type ResultTag interface { - Result() driver.Result - Tag() string - } - - tests := []struct { - query string - tag string - ra int64 - }{ - { - query: "CREATE TEMP TABLE temp (a int)", - tag: "CREATE TABLE", - }, - { - query: "INSERT INTO temp VALUES (1), (2)", - tag: "INSERT", - ra: 2, - }, - { - query: "SELECT 1", - }, - // A SELECT anywhere should take precedent. - { - query: "SELECT 1; INSERT INTO temp VALUES (1), (2)", - }, - { - query: "INSERT INTO temp VALUES (1), (2); SELECT 1", - }, - // Multiple statements that don't return rows should return the last tag. - { - query: "CREATE TEMP TABLE t (a int); DROP TABLE t", - tag: "DROP TABLE", - }, - // Ensure a rows-returning query in any position among various tags-returing - // statements will prefer the rows. - { - query: "SELECT 1; CREATE TEMP TABLE t (a int); DROP TABLE t", - }, - { - query: "CREATE TEMP TABLE t (a int); SELECT 1; DROP TABLE t", - }, - { - query: "CREATE TEMP TABLE t (a int); DROP TABLE t; SELECT 1", - }, - } - - // If this is the only test run, this will correct the connection string. - openTestConn(t).Close() - - conn, err := Open("") - if err != nil { - t.Fatal(err) - } - defer conn.Close() - q := conn.(driver.QueryerContext) - - for _, test := range tests { - if rows, err := q.QueryContext(context.Background(), test.query, nil); err != nil { - t.Fatalf("%s: %s", test.query, err) - } else { - r := rows.(ResultTag) - if tag := r.Tag(); tag != test.tag { - t.Fatalf("%s: unexpected tag %q", test.query, tag) - } - res := r.Result() - if ra, _ := res.RowsAffected(); ra != test.ra { - t.Fatalf("%s: unexpected rows affected: %d", test.query, ra) - } - rows.Close() - } - } -} - -// TestQuickClose tests that closing a query early allows a subsequent query to work. -func TestQuickClose(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - tx, err := db.Begin() - if err != nil { - t.Fatal(err) - } - rows, err := tx.Query("SELECT 1; SELECT 2;") - if err != nil { - t.Fatal(err) - } - if err := rows.Close(); err != nil { - t.Fatal(err) - } - - var id int - if err := tx.QueryRow("SELECT 3").Scan(&id); err != nil { - t.Fatal(err) - } - if id != 3 { - t.Fatalf("unexpected %d", id) - } - if err := tx.Commit(); err != nil { - t.Fatal(err) - } -} - -func TestMultipleResult(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - rows, err := db.Query(` - begin; - select * from information_schema.tables limit 1; - select * from information_schema.columns limit 2; - commit; - `) - if err != nil { - t.Fatal(err) - } - type set struct { - cols []string - rowCount int - } - buf := []*set{} - for { - cols, err := rows.Columns() - if err != nil { - t.Fatal(err) - } - s := &set{ - cols: cols, - } - buf = append(buf, s) - - for rows.Next() { - s.rowCount++ - } - if !rows.NextResultSet() { - break - } - } - if len(buf) != 2 { - t.Fatalf("got %d sets, expected 2", len(buf)) - } - if len(buf[0].cols) == len(buf[1].cols) || len(buf[1].cols) == 0 { - t.Fatal("invalid cols size, expected different column count and greater then zero") - } - if buf[0].rowCount != 1 || buf[1].rowCount != 2 { - t.Fatal("incorrect number of rows returned") - } -} - -func TestMultipleEmptyResult(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - rows, err := db.Query("select 1 where false; select 2") - if err != nil { - t.Fatal(err) - } - defer rows.Close() - - for rows.Next() { - t.Fatal("unexpected row") - } - if !rows.NextResultSet() { - t.Fatal("expected more result sets", rows.Err()) - } - for rows.Next() { - var i int - if err := rows.Scan(&i); err != nil { - t.Fatal(err) - } - if i != 2 { - t.Fatalf("expected 2, got %d", i) - } - } - if rows.NextResultSet() { - t.Fatal("unexpected result set") - } -} - -func TestCopyInStmtAffectedRows(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - _, err := db.Exec("CREATE TEMP TABLE temp (a int)") - if err != nil { - t.Fatal(err) - } - - txn, err := db.BeginTx(context.TODO(), nil) - if err != nil { - t.Fatal(err) - } - - copyStmt, err := txn.Prepare(CopyIn("temp", "a")) - if err != nil { - t.Fatal(err) - } - - res, err := copyStmt.Exec() - if err != nil { - t.Fatal(err) - } - - res.RowsAffected() - res.LastInsertId() -} - -func TestConnPrepareContext(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - tests := []struct { - name string - ctx func() (context.Context, context.CancelFunc) - sql string - err error - }{ - { - name: "context.Background", - ctx: func() (context.Context, context.CancelFunc) { - return context.Background(), nil - }, - sql: "SELECT 1", - err: nil, - }, - { - name: "context.WithTimeout exceeded", - ctx: func() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), -time.Minute) - }, - sql: "SELECT 1", - err: context.DeadlineExceeded, - }, - { - name: "context.WithTimeout", - ctx: func() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), time.Minute) - }, - sql: "SELECT 1", - err: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctx, cancel := tt.ctx() - if cancel != nil { - defer cancel() - } - _, err := db.PrepareContext(ctx, tt.sql) - switch { - case (err != nil) != (tt.err != nil): - t.Fatalf("conn.PrepareContext() unexpected nil err got = %v, expected = %v", err, tt.err) - case (err != nil && tt.err != nil) && (err.Error() != tt.err.Error()): - t.Errorf("conn.PrepareContext() got = %v, expected = %v", err.Error(), tt.err.Error()) - } - }) - } -} - -func TestStmtQueryContext(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - tests := []struct { - name string - ctx func() (context.Context, context.CancelFunc) - sql string - err error - }{ - { - name: "context.Background", - ctx: func() (context.Context, context.CancelFunc) { - return context.Background(), nil - }, - sql: "SELECT pg_sleep(1);", - err: nil, - }, - { - name: "context.WithTimeout exceeded", - ctx: func() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), 1*time.Second) - }, - sql: "SELECT pg_sleep(10);", - err: &Error{Message: "canceling statement due to user request"}, - }, - { - name: "context.WithTimeout", - ctx: func() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), time.Minute) - }, - sql: "SELECT pg_sleep(1);", - err: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctx, cancel := tt.ctx() - if cancel != nil { - defer cancel() - } - stmt, err := db.PrepareContext(ctx, tt.sql) - if err != nil { - t.Fatal(err) - } - _, err = stmt.QueryContext(ctx) - switch { - case (err != nil) != (tt.err != nil): - t.Fatalf("stmt.QueryContext() unexpected nil err got = %v, expected = %v", err, tt.err) - case (err != nil && tt.err != nil) && (err.Error() != tt.err.Error()): - t.Errorf("stmt.QueryContext() got = %v, expected = %v", err.Error(), tt.err.Error()) - } - }) - } -} - -func TestStmtExecContext(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - tests := []struct { - name string - ctx func() (context.Context, context.CancelFunc) - sql string - err error - }{ - { - name: "context.Background", - ctx: func() (context.Context, context.CancelFunc) { - return context.Background(), nil - }, - sql: "SELECT pg_sleep(1);", - err: nil, - }, - { - name: "context.WithTimeout exceeded", - ctx: func() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), 1*time.Second) - }, - sql: "SELECT pg_sleep(10);", - err: &Error{Message: "canceling statement due to user request"}, - }, - { - name: "context.WithTimeout", - ctx: func() (context.Context, context.CancelFunc) { - return context.WithTimeout(context.Background(), time.Minute) - }, - sql: "SELECT pg_sleep(1);", - err: nil, - }, - } - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - ctx, cancel := tt.ctx() - if cancel != nil { - defer cancel() - } - stmt, err := db.PrepareContext(ctx, tt.sql) - if err != nil { - t.Fatal(err) - } - _, err = stmt.ExecContext(ctx) - switch { - case (err != nil) != (tt.err != nil): - t.Fatalf("stmt.ExecContext() unexpected nil err got = %v, expected = %v", err, tt.err) - case (err != nil && tt.err != nil) && (err.Error() != tt.err.Error()): - t.Errorf("stmt.ExecContext() got = %v, expected = %v", err.Error(), tt.err.Error()) - } - }) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/connector.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/connector.go deleted file mode 100644 index d7d472615..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/connector.go +++ /dev/null @@ -1,115 +0,0 @@ -package pq - -import ( - "context" - "database/sql/driver" - "errors" - "fmt" - "os" - "strings" -) - -// Connector represents a fixed configuration for the pq driver with a given -// name. Connector satisfies the database/sql/driver Connector interface and -// can be used to create any number of DB Conn's via the database/sql OpenDB -// function. -// -// See https://golang.org/pkg/database/sql/driver/#Connector. -// See https://golang.org/pkg/database/sql/#OpenDB. -type Connector struct { - opts values - dialer Dialer -} - -// Connect returns a connection to the database using the fixed configuration -// of this Connector. Context is not used. -func (c *Connector) Connect(ctx context.Context) (driver.Conn, error) { - return c.open(ctx) -} - -// Driver returns the underlying driver of this Connector. -func (c *Connector) Driver() driver.Driver { - return &Driver{} -} - -// NewConnector returns a connector for the pq driver in a fixed configuration -// with the given dsn. The returned connector can be used to create any number -// of equivalent Conn's. The returned connector is intended to be used with -// database/sql.OpenDB. -// -// See https://golang.org/pkg/database/sql/driver/#Connector. -// See https://golang.org/pkg/database/sql/#OpenDB. -func NewConnector(dsn string) (*Connector, error) { - var err error - o := make(values) - - // A number of defaults are applied here, in this order: - // - // * Very low precedence defaults applied in every situation - // * Environment variables - // * Explicitly passed connection information - o["host"] = "localhost" - o["port"] = "5432" - // N.B.: Extra float digits should be set to 3, but that breaks - // Postgres 8.4 and older, where the max is 2. - o["extra_float_digits"] = "2" - for k, v := range parseEnviron(os.Environ()) { - o[k] = v - } - - if strings.HasPrefix(dsn, "postgres://") || strings.HasPrefix(dsn, "postgresql://") { - dsn, err = ParseURL(dsn) - if err != nil { - return nil, err - } - } - - if err := parseOpts(dsn, o); err != nil { - return nil, err - } - - // Use the "fallback" application name if necessary - if fallback, ok := o["fallback_application_name"]; ok { - if _, ok := o["application_name"]; !ok { - o["application_name"] = fallback - } - } - - // We can't work with any client_encoding other than UTF-8 currently. - // However, we have historically allowed the user to set it to UTF-8 - // explicitly, and there's no reason to break such programs, so allow that. - // Note that the "options" setting could also set client_encoding, but - // parsing its value is not worth it. Instead, we always explicitly send - // client_encoding as a separate run-time parameter, which should override - // anything set in options. - if enc, ok := o["client_encoding"]; ok && !isUTF8(enc) { - return nil, errors.New("client_encoding must be absent or 'UTF8'") - } - o["client_encoding"] = "UTF8" - // DateStyle needs a similar treatment. - if datestyle, ok := o["datestyle"]; ok { - if datestyle != "ISO, MDY" { - return nil, fmt.Errorf("setting datestyle must be absent or %v; got %v", "ISO, MDY", datestyle) - } - } else { - o["datestyle"] = "ISO, MDY" - } - - // If a user is not provided by any other means, the last - // resort is to use the current operating system provided user - // name. - if _, ok := o["user"]; !ok { - u, err := userCurrent() - if err != nil { - return nil, err - } - o["user"] = u - } - - // SSL is not necessary or supported over UNIX domain sockets - if network, _ := network(o); network == "unix" { - o["sslmode"] = "disable" - } - - return &Connector{opts: o, dialer: defaultDialer{}}, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/connector_example_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/connector_example_test.go deleted file mode 100644 index dbae4db52..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/connector_example_test.go +++ /dev/null @@ -1,30 +0,0 @@ -//go:build go1.10 -// +build go1.10 - -package pq_test - -import ( - "database/sql" - "fmt" - - "github.com/lib/pq" -) - -func ExampleNewConnector() { - name := "" - connector, err := pq.NewConnector(name) - if err != nil { - fmt.Println(err) - return - } - db := sql.OpenDB(connector) - defer db.Close() - - // Use the DB - txn, err := db.Begin() - if err != nil { - fmt.Println(err) - return - } - txn.Rollback() -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/connector_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/connector_test.go deleted file mode 100644 index d68810e9e..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/connector_test.go +++ /dev/null @@ -1,68 +0,0 @@ -//go:build go1.10 -// +build go1.10 - -package pq - -import ( - "context" - "database/sql" - "database/sql/driver" - "testing" -) - -func TestNewConnector_WorksWithOpenDB(t *testing.T) { - name := "" - c, err := NewConnector(name) - if err != nil { - t.Fatal(err) - } - db := sql.OpenDB(c) - defer db.Close() - // database/sql might not call our Open at all unless we do something with - // the connection - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - txn.Rollback() -} - -func TestNewConnector_Connect(t *testing.T) { - name := "" - c, err := NewConnector(name) - if err != nil { - t.Fatal(err) - } - db, err := c.Connect(context.Background()) - if err != nil { - t.Fatal(err) - } - defer db.Close() - // database/sql might not call our Open at all unless we do something with - // the connection - txn, err := db.(driver.ConnBeginTx).BeginTx(context.Background(), driver.TxOptions{}) - if err != nil { - t.Fatal(err) - } - txn.Rollback() -} - -func TestNewConnector_Driver(t *testing.T) { - name := "" - c, err := NewConnector(name) - if err != nil { - t.Fatal(err) - } - db, err := c.Driver().Open(name) - if err != nil { - t.Fatal(err) - } - defer db.Close() - // database/sql might not call our Open at all unless we do something with - // the connection - txn, err := db.(driver.ConnBeginTx).BeginTx(context.Background(), driver.TxOptions{}) - if err != nil { - t.Fatal(err) - } - txn.Rollback() -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/copy.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/copy.go deleted file mode 100644 index c072bc3bc..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/copy.go +++ /dev/null @@ -1,303 +0,0 @@ -package pq - -import ( - "database/sql/driver" - "encoding/binary" - "errors" - "fmt" - "sync" -) - -var ( - errCopyInClosed = errors.New("pq: copyin statement has already been closed") - errBinaryCopyNotSupported = errors.New("pq: only text format supported for COPY") - errCopyToNotSupported = errors.New("pq: COPY TO is not supported") - errCopyNotSupportedOutsideTxn = errors.New("pq: COPY is only allowed inside a transaction") - errCopyInProgress = errors.New("pq: COPY in progress") -) - -// CopyIn creates a COPY FROM statement which can be prepared with -// Tx.Prepare(). The target table should be visible in search_path. -func CopyIn(table string, columns ...string) string { - stmt := "COPY " + QuoteIdentifier(table) + " (" - for i, col := range columns { - if i != 0 { - stmt += ", " - } - stmt += QuoteIdentifier(col) - } - stmt += ") FROM STDIN" - return stmt -} - -// CopyInSchema creates a COPY FROM statement which can be prepared with -// Tx.Prepare(). -func CopyInSchema(schema, table string, columns ...string) string { - stmt := "COPY " + QuoteIdentifier(schema) + "." + QuoteIdentifier(table) + " (" - for i, col := range columns { - if i != 0 { - stmt += ", " - } - stmt += QuoteIdentifier(col) - } - stmt += ") FROM STDIN" - return stmt -} - -type copyin struct { - cn *conn - buffer []byte - rowData chan []byte - done chan bool - - closed bool - - mu struct { - sync.Mutex - err error - driver.Result - } -} - -const ciBufferSize = 64 * 1024 - -// flush buffer before the buffer is filled up and needs reallocation -const ciBufferFlushSize = 63 * 1024 - -func (cn *conn) prepareCopyIn(q string) (_ driver.Stmt, err error) { - if !cn.isInTransaction() { - return nil, errCopyNotSupportedOutsideTxn - } - - ci := ©in{ - cn: cn, - buffer: make([]byte, 0, ciBufferSize), - rowData: make(chan []byte), - done: make(chan bool, 1), - } - // add CopyData identifier + 4 bytes for message length - ci.buffer = append(ci.buffer, 'd', 0, 0, 0, 0) - - b := cn.writeBuf('Q') - b.string(q) - cn.send(b) - -awaitCopyInResponse: - for { - t, r := cn.recv1() - switch t { - case 'G': - if r.byte() != 0 { - err = errBinaryCopyNotSupported - break awaitCopyInResponse - } - go ci.resploop() - return ci, nil - case 'H': - err = errCopyToNotSupported - break awaitCopyInResponse - case 'E': - err = parseError(r) - case 'Z': - if err == nil { - ci.setBad(driver.ErrBadConn) - errorf("unexpected ReadyForQuery in response to COPY") - } - cn.processReadyForQuery(r) - return nil, err - default: - ci.setBad(driver.ErrBadConn) - errorf("unknown response for copy query: %q", t) - } - } - - // something went wrong, abort COPY before we return - b = cn.writeBuf('f') - b.string(err.Error()) - cn.send(b) - - for { - t, r := cn.recv1() - switch t { - case 'c', 'C', 'E': - case 'Z': - // correctly aborted, we're done - cn.processReadyForQuery(r) - return nil, err - default: - ci.setBad(driver.ErrBadConn) - errorf("unknown response for CopyFail: %q", t) - } - } -} - -func (ci *copyin) flush(buf []byte) { - // set message length (without message identifier) - binary.BigEndian.PutUint32(buf[1:], uint32(len(buf)-1)) - - _, err := ci.cn.c.Write(buf) - if err != nil { - panic(err) - } -} - -func (ci *copyin) resploop() { - for { - var r readBuf - t, err := ci.cn.recvMessage(&r) - if err != nil { - ci.setBad(driver.ErrBadConn) - ci.setError(err) - ci.done <- true - return - } - switch t { - case 'C': - // complete - res, _ := ci.cn.parseComplete(r.string()) - ci.setResult(res) - case 'N': - if n := ci.cn.noticeHandler; n != nil { - n(parseError(&r)) - } - case 'Z': - ci.cn.processReadyForQuery(&r) - ci.done <- true - return - case 'E': - err := parseError(&r) - ci.setError(err) - default: - ci.setBad(driver.ErrBadConn) - ci.setError(fmt.Errorf("unknown response during CopyIn: %q", t)) - ci.done <- true - return - } - } -} - -func (ci *copyin) setBad(err error) { - ci.cn.err.set(err) -} - -func (ci *copyin) getBad() error { - return ci.cn.err.get() -} - -func (ci *copyin) err() error { - ci.mu.Lock() - err := ci.mu.err - ci.mu.Unlock() - return err -} - -// setError() sets ci.err if one has not been set already. Caller must not be -// holding ci.Mutex. -func (ci *copyin) setError(err error) { - ci.mu.Lock() - if ci.mu.err == nil { - ci.mu.err = err - } - ci.mu.Unlock() -} - -func (ci *copyin) setResult(result driver.Result) { - ci.mu.Lock() - ci.mu.Result = result - ci.mu.Unlock() -} - -func (ci *copyin) getResult() driver.Result { - ci.mu.Lock() - result := ci.mu.Result - ci.mu.Unlock() - if result == nil { - return driver.RowsAffected(0) - } - return result -} - -func (ci *copyin) NumInput() int { - return -1 -} - -func (ci *copyin) Query(v []driver.Value) (r driver.Rows, err error) { - return nil, ErrNotSupported -} - -// Exec inserts values into the COPY stream. The insert is asynchronous -// and Exec can return errors from previous Exec calls to the same -// COPY stmt. -// -// You need to call Exec(nil) to sync the COPY stream and to get any -// errors from pending data, since Stmt.Close() doesn't return errors -// to the user. -func (ci *copyin) Exec(v []driver.Value) (r driver.Result, err error) { - if ci.closed { - return nil, errCopyInClosed - } - - if err := ci.getBad(); err != nil { - return nil, err - } - defer ci.cn.errRecover(&err) - - if err := ci.err(); err != nil { - return nil, err - } - - if len(v) == 0 { - if err := ci.Close(); err != nil { - return driver.RowsAffected(0), err - } - - return ci.getResult(), nil - } - - numValues := len(v) - for i, value := range v { - ci.buffer = appendEncodedText(&ci.cn.parameterStatus, ci.buffer, value) - if i < numValues-1 { - ci.buffer = append(ci.buffer, '\t') - } - } - - ci.buffer = append(ci.buffer, '\n') - - if len(ci.buffer) > ciBufferFlushSize { - ci.flush(ci.buffer) - // reset buffer, keep bytes for message identifier and length - ci.buffer = ci.buffer[:5] - } - - return driver.RowsAffected(0), nil -} - -func (ci *copyin) Close() (err error) { - if ci.closed { // Don't do anything, we're already closed - return nil - } - ci.closed = true - - if err := ci.getBad(); err != nil { - return err - } - defer ci.cn.errRecover(&err) - - if len(ci.buffer) > 0 { - ci.flush(ci.buffer) - } - // Avoid touching the scratch buffer as resploop could be using it. - err = ci.cn.sendSimpleMessage('c') - if err != nil { - return err - } - - <-ci.done - ci.cn.inCopy = false - - if err := ci.err(); err != nil { - return err - } - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/copy_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/copy_test.go deleted file mode 100644 index 852f1be5a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/copy_test.go +++ /dev/null @@ -1,502 +0,0 @@ -package pq - -import ( - "bytes" - "database/sql" - "database/sql/driver" - "fmt" - "net" - "strings" - "testing" - "time" -) - -func TestCopyInStmt(t *testing.T) { - stmt := CopyIn("table name") - if stmt != `COPY "table name" () FROM STDIN` { - t.Fatal(stmt) - } - - stmt = CopyIn("table name", "column 1", "column 2") - if stmt != `COPY "table name" ("column 1", "column 2") FROM STDIN` { - t.Fatal(stmt) - } - - stmt = CopyIn(`table " name """`, `co"lumn""`) - if stmt != `COPY "table "" name """"""" ("co""lumn""""") FROM STDIN` { - t.Fatal(stmt) - } -} - -func TestCopyInSchemaStmt(t *testing.T) { - stmt := CopyInSchema("schema name", "table name") - if stmt != `COPY "schema name"."table name" () FROM STDIN` { - t.Fatal(stmt) - } - - stmt = CopyInSchema("schema name", "table name", "column 1", "column 2") - if stmt != `COPY "schema name"."table name" ("column 1", "column 2") FROM STDIN` { - t.Fatal(stmt) - } - - stmt = CopyInSchema(`schema " name """`, `table " name """`, `co"lumn""`) - if stmt != `COPY "schema "" name """"""".`+ - `"table "" name """"""" ("co""lumn""""") FROM STDIN` { - t.Fatal(stmt) - } -} - -func TestCopyInMultipleValues(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)") - if err != nil { - t.Fatal(err) - } - - stmt, err := txn.Prepare(CopyIn("temp", "a", "b")) - if err != nil { - t.Fatal(err) - } - - longString := strings.Repeat("#", 500) - - for i := 0; i < 500; i++ { - _, err = stmt.Exec(int64(i), longString) - if err != nil { - t.Fatal(err) - } - } - - result, err := stmt.Exec() - if err != nil { - t.Fatal(err) - } - - rowsAffected, err := result.RowsAffected() - if err != nil { - t.Fatal(err) - } - - if rowsAffected != 500 { - t.Fatalf("expected 500 rows affected, not %d", rowsAffected) - } - - err = stmt.Close() - if err != nil { - t.Fatal(err) - } - - var num int - err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num) - if err != nil { - t.Fatal(err) - } - - if num != 500 { - t.Fatalf("expected 500 items, not %d", num) - } -} - -func TestCopyInRaiseStmtTrigger(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - if getServerVersion(t, db) < 90000 { - var exists int - err := db.QueryRow("SELECT 1 FROM pg_language WHERE lanname = 'plpgsql'").Scan(&exists) - if err == sql.ErrNoRows { - t.Skip("language PL/PgSQL does not exist; skipping TestCopyInRaiseStmtTrigger") - } else if err != nil { - t.Fatal(err) - } - } - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)") - if err != nil { - t.Fatal(err) - } - - _, err = txn.Exec(` - CREATE OR REPLACE FUNCTION pg_temp.temptest() - RETURNS trigger AS - $BODY$ begin - raise notice 'Hello world'; - return new; - end $BODY$ - LANGUAGE plpgsql`) - if err != nil { - t.Fatal(err) - } - - _, err = txn.Exec(` - CREATE TRIGGER temptest_trigger - BEFORE INSERT - ON temp - FOR EACH ROW - EXECUTE PROCEDURE pg_temp.temptest()`) - if err != nil { - t.Fatal(err) - } - - stmt, err := txn.Prepare(CopyIn("temp", "a", "b")) - if err != nil { - t.Fatal(err) - } - - longString := strings.Repeat("#", 500) - - _, err = stmt.Exec(int64(1), longString) - if err != nil { - t.Fatal(err) - } - - _, err = stmt.Exec() - if err != nil { - t.Fatal(err) - } - - err = stmt.Close() - if err != nil { - t.Fatal(err) - } - - var num int - err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num) - if err != nil { - t.Fatal(err) - } - - if num != 1 { - t.Fatalf("expected 1 items, not %d", num) - } -} - -func TestCopyInTypes(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER, text VARCHAR, blob BYTEA, nothing VARCHAR)") - if err != nil { - t.Fatal(err) - } - - stmt, err := txn.Prepare(CopyIn("temp", "num", "text", "blob", "nothing")) - if err != nil { - t.Fatal(err) - } - - _, err = stmt.Exec(int64(1234567890), "Héllö\n ☃!\r\t\\", []byte{0, 255, 9, 10, 13}, nil) - if err != nil { - t.Fatal(err) - } - - _, err = stmt.Exec() - if err != nil { - t.Fatal(err) - } - - err = stmt.Close() - if err != nil { - t.Fatal(err) - } - - var num int - var text string - var blob []byte - var nothing sql.NullString - - err = txn.QueryRow("SELECT * FROM temp").Scan(&num, &text, &blob, ¬hing) - if err != nil { - t.Fatal(err) - } - - if num != 1234567890 { - t.Fatal("unexpected result", num) - } - if text != "Héllö\n ☃!\r\t\\" { - t.Fatal("unexpected result", text) - } - if !bytes.Equal(blob, []byte{0, 255, 9, 10, 13}) { - t.Fatal("unexpected result", blob) - } - if nothing.Valid { - t.Fatal("unexpected result", nothing.String) - } -} - -func TestCopyInWrongType(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)") - if err != nil { - t.Fatal(err) - } - - stmt, err := txn.Prepare(CopyIn("temp", "num")) - if err != nil { - t.Fatal(err) - } - defer stmt.Close() - - _, err = stmt.Exec("Héllö\n ☃!\r\t\\") - if err != nil { - t.Fatal(err) - } - - _, err = stmt.Exec() - if err == nil { - t.Fatal("expected error") - } - if pge := err.(*Error); pge.Code.Name() != "invalid_text_representation" { - t.Fatalf("expected 'invalid input syntax for integer' error, got %s (%+v)", pge.Code.Name(), pge) - } -} - -func TestCopyOutsideOfTxnError(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - _, err := db.Prepare(CopyIn("temp", "num")) - if err == nil { - t.Fatal("COPY outside of transaction did not return an error") - } - if err != errCopyNotSupportedOutsideTxn { - t.Fatalf("expected %s, got %s", err, err.Error()) - } -} - -func TestCopyInBinaryError(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)") - if err != nil { - t.Fatal(err) - } - _, err = txn.Prepare("COPY temp (num) FROM STDIN WITH binary") - if err != errBinaryCopyNotSupported { - t.Fatalf("expected %s, got %+v", errBinaryCopyNotSupported, err) - } - // check that the protocol is in a valid state - err = txn.Rollback() - if err != nil { - t.Fatal(err) - } -} - -func TestCopyFromError(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMP TABLE temp (num INTEGER)") - if err != nil { - t.Fatal(err) - } - _, err = txn.Prepare("COPY temp (num) TO STDOUT") - if err != errCopyToNotSupported { - t.Fatalf("expected %s, got %+v", errCopyToNotSupported, err) - } - // check that the protocol is in a valid state - err = txn.Rollback() - if err != nil { - t.Fatal(err) - } -} - -func TestCopySyntaxError(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Prepare("COPY ") - if err == nil { - t.Fatal("expected error") - } - if pge := err.(*Error); pge.Code.Name() != "syntax_error" { - t.Fatalf("expected syntax error, got %s (%+v)", pge.Code.Name(), pge) - } - // check that the protocol is in a valid state - err = txn.Rollback() - if err != nil { - t.Fatal(err) - } -} - -// Tests for connection errors in copyin.resploop() -func TestCopyRespLoopConnectionError(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - var pid int - err = txn.QueryRow("SELECT pg_backend_pid()").Scan(&pid) - if err != nil { - t.Fatal(err) - } - - _, err = txn.Exec("CREATE TEMP TABLE temp (a int)") - if err != nil { - t.Fatal(err) - } - - stmt, err := txn.Prepare(CopyIn("temp", "a")) - if err != nil { - t.Fatal(err) - } - defer stmt.Close() - - _, err = db.Exec("SELECT pg_terminate_backend($1)", pid) - if err != nil { - t.Fatal(err) - } - - if getServerVersion(t, db) < 90500 { - // We have to try and send something over, since postgres before - // version 9.5 won't process SIGTERMs while it's waiting for - // CopyData/CopyEnd messages; see tcop/postgres.c. - _, err = stmt.Exec(1) - if err != nil { - t.Fatal(err) - } - } - retry(t, time.Second*5, func() error { - _, err = stmt.Exec() - if err == nil { - return fmt.Errorf("expected error") - } - return nil - }) - switch pge := err.(type) { - case *Error: - if pge.Code.Name() != "admin_shutdown" { - t.Fatalf("expected admin_shutdown, got %s", pge.Code.Name()) - } - case *net.OpError: - // ignore - default: - if err == driver.ErrBadConn { - // likely an EPIPE - } else if err == errCopyInClosed { - // ignore - } else { - t.Fatalf("unexpected error, got %+#v", err) - } - } - - _ = stmt.Close() -} - -// retry executes f in a backoff loop until it doesn't return an error. If this -// doesn't happen within duration, t.Fatal is called with the latest error. -func retry(t *testing.T, duration time.Duration, f func() error) { - start := time.Now() - next := time.Millisecond * 100 - for { - err := f() - if err == nil { - return - } - if time.Since(start) > duration { - t.Fatal(err) - } - time.Sleep(next) - next *= 2 - } -} - -func BenchmarkCopyIn(b *testing.B) { - db := openTestConn(b) - defer db.Close() - - txn, err := db.Begin() - if err != nil { - b.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("CREATE TEMP TABLE temp (a int, b varchar)") - if err != nil { - b.Fatal(err) - } - - stmt, err := txn.Prepare(CopyIn("temp", "a", "b")) - if err != nil { - b.Fatal(err) - } - - for i := 0; i < b.N; i++ { - _, err = stmt.Exec(int64(i), "hello world!") - if err != nil { - b.Fatal(err) - } - } - - _, err = stmt.Exec() - if err != nil { - b.Fatal(err) - } - - err = stmt.Close() - if err != nil { - b.Fatal(err) - } - - var num int - err = txn.QueryRow("SELECT COUNT(*) FROM temp").Scan(&num) - if err != nil { - b.Fatal(err) - } - - if num != b.N { - b.Fatalf("expected %d items, not %d", b.N, num) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/doc.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/doc.go deleted file mode 100644 index b57184801..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/doc.go +++ /dev/null @@ -1,268 +0,0 @@ -/* -Package pq is a pure Go Postgres driver for the database/sql package. - -In most cases clients will use the database/sql package instead of -using this package directly. For example: - - import ( - "database/sql" - - _ "github.com/lib/pq" - ) - - func main() { - connStr := "user=pqgotest dbname=pqgotest sslmode=verify-full" - db, err := sql.Open("postgres", connStr) - if err != nil { - log.Fatal(err) - } - - age := 21 - rows, err := db.Query("SELECT name FROM users WHERE age = $1", age) - … - } - -You can also connect to a database using a URL. For example: - - connStr := "postgres://pqgotest:password@localhost/pqgotest?sslmode=verify-full" - db, err := sql.Open("postgres", connStr) - - -Connection String Parameters - - -Similarly to libpq, when establishing a connection using pq you are expected to -supply a connection string containing zero or more parameters. -A subset of the connection parameters supported by libpq are also supported by pq. -Additionally, pq also lets you specify run-time parameters (such as search_path or work_mem) -directly in the connection string. This is different from libpq, which does not allow -run-time parameters in the connection string, instead requiring you to supply -them in the options parameter. - -For compatibility with libpq, the following special connection parameters are -supported: - - * dbname - The name of the database to connect to - * user - The user to sign in as - * password - The user's password - * host - The host to connect to. Values that start with / are for unix - domain sockets. (default is localhost) - * port - The port to bind to. (default is 5432) - * sslmode - Whether or not to use SSL (default is require, this is not - the default for libpq) - * fallback_application_name - An application_name to fall back to if one isn't provided. - * connect_timeout - Maximum wait for connection, in seconds. Zero or - not specified means wait indefinitely. - * sslcert - Cert file location. The file must contain PEM encoded data. - * sslkey - Key file location. The file must contain PEM encoded data. - * sslrootcert - The location of the root certificate file. The file - must contain PEM encoded data. - -Valid values for sslmode are: - - * disable - No SSL - * require - Always SSL (skip verification) - * verify-ca - Always SSL (verify that the certificate presented by the - server was signed by a trusted CA) - * verify-full - Always SSL (verify that the certification presented by - the server was signed by a trusted CA and the server host name - matches the one in the certificate) - -See http://www.postgresql.org/docs/current/static/libpq-connect.html#LIBPQ-CONNSTRING -for more information about connection string parameters. - -Use single quotes for values that contain whitespace: - - "user=pqgotest password='with spaces'" - -A backslash will escape the next character in values: - - "user=space\ man password='it\'s valid'" - -Note that the connection parameter client_encoding (which sets the -text encoding for the connection) may be set but must be "UTF8", -matching with the same rules as Postgres. It is an error to provide -any other value. - -In addition to the parameters listed above, any run-time parameter that can be -set at backend start time can be set in the connection string. For more -information, see -http://www.postgresql.org/docs/current/static/runtime-config.html. - -Most environment variables as specified at http://www.postgresql.org/docs/current/static/libpq-envars.html -supported by libpq are also supported by pq. If any of the environment -variables not supported by pq are set, pq will panic during connection -establishment. Environment variables have a lower precedence than explicitly -provided connection parameters. - -The pgpass mechanism as described in http://www.postgresql.org/docs/current/static/libpq-pgpass.html -is supported, but on Windows PGPASSFILE must be specified explicitly. - - -Queries - - -database/sql does not dictate any specific format for parameter -markers in query strings, and pq uses the Postgres-native ordinal markers, -as shown above. The same marker can be reused for the same parameter: - - rows, err := db.Query(`SELECT name FROM users WHERE favorite_fruit = $1 - OR age BETWEEN $2 AND $2 + 3`, "orange", 64) - -pq does not support the LastInsertId() method of the Result type in database/sql. -To return the identifier of an INSERT (or UPDATE or DELETE), use the Postgres -RETURNING clause with a standard Query or QueryRow call: - - var userid int - err := db.QueryRow(`INSERT INTO users(name, favorite_fruit, age) - VALUES('beatrice', 'starfruit', 93) RETURNING id`).Scan(&userid) - -For more details on RETURNING, see the Postgres documentation: - - http://www.postgresql.org/docs/current/static/sql-insert.html - http://www.postgresql.org/docs/current/static/sql-update.html - http://www.postgresql.org/docs/current/static/sql-delete.html - -For additional instructions on querying see the documentation for the database/sql package. - - -Data Types - - -Parameters pass through driver.DefaultParameterConverter before they are handled -by this package. When the binary_parameters connection option is enabled, -[]byte values are sent directly to the backend as data in binary format. - -This package returns the following types for values from the PostgreSQL backend: - - - integer types smallint, integer, and bigint are returned as int64 - - floating-point types real and double precision are returned as float64 - - character types char, varchar, and text are returned as string - - temporal types date, time, timetz, timestamp, and timestamptz are - returned as time.Time - - the boolean type is returned as bool - - the bytea type is returned as []byte - -All other types are returned directly from the backend as []byte values in text format. - - -Errors - - -pq may return errors of type *pq.Error which can be interrogated for error details: - - if err, ok := err.(*pq.Error); ok { - fmt.Println("pq error:", err.Code.Name()) - } - -See the pq.Error type for details. - - -Bulk imports - -You can perform bulk imports by preparing a statement returned by pq.CopyIn (or -pq.CopyInSchema) in an explicit transaction (sql.Tx). The returned statement -handle can then be repeatedly "executed" to copy data into the target table. -After all data has been processed you should call Exec() once with no arguments -to flush all buffered data. Any call to Exec() might return an error which -should be handled appropriately, but because of the internal buffering an error -returned by Exec() might not be related to the data passed in the call that -failed. - -CopyIn uses COPY FROM internally. It is not possible to COPY outside of an -explicit transaction in pq. - -Usage example: - - txn, err := db.Begin() - if err != nil { - log.Fatal(err) - } - - stmt, err := txn.Prepare(pq.CopyIn("users", "name", "age")) - if err != nil { - log.Fatal(err) - } - - for _, user := range users { - _, err = stmt.Exec(user.Name, int64(user.Age)) - if err != nil { - log.Fatal(err) - } - } - - _, err = stmt.Exec() - if err != nil { - log.Fatal(err) - } - - err = stmt.Close() - if err != nil { - log.Fatal(err) - } - - err = txn.Commit() - if err != nil { - log.Fatal(err) - } - - -Notifications - - -PostgreSQL supports a simple publish/subscribe model over database -connections. See http://www.postgresql.org/docs/current/static/sql-notify.html -for more information about the general mechanism. - -To start listening for notifications, you first have to open a new connection -to the database by calling NewListener. This connection can not be used for -anything other than LISTEN / NOTIFY. Calling Listen will open a "notification -channel"; once a notification channel is open, a notification generated on that -channel will effect a send on the Listener.Notify channel. A notification -channel will remain open until Unlisten is called, though connection loss might -result in some notifications being lost. To solve this problem, Listener sends -a nil pointer over the Notify channel any time the connection is re-established -following a connection loss. The application can get information about the -state of the underlying connection by setting an event callback in the call to -NewListener. - -A single Listener can safely be used from concurrent goroutines, which means -that there is often no need to create more than one Listener in your -application. However, a Listener is always connected to a single database, so -you will need to create a new Listener instance for every database you want to -receive notifications in. - -The channel name in both Listen and Unlisten is case sensitive, and can contain -any characters legal in an identifier (see -http://www.postgresql.org/docs/current/static/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS -for more information). Note that the channel name will be truncated to 63 -bytes by the PostgreSQL server. - -You can find a complete, working example of Listener usage at -https://godoc.org/github.com/lib/pq/example/listen. - - -Kerberos Support - - -If you need support for Kerberos authentication, add the following to your main -package: - - import "github.com/lib/pq/auth/kerberos" - - func init() { - pq.RegisterGSSProvider(func() (pq.Gss, error) { return kerberos.NewGSS() }) - } - -This package is in a separate module so that users who don't need Kerberos -don't have to download unnecessary dependencies. - -When imported, additional connection string parameters are supported: - - * krbsrvname - GSS (Kerberos) service name when constructing the - SPN (default is `postgres`). This will be combined with the host - to form the full SPN: `krbsrvname/host`. - * krbspn - GSS (Kerberos) SPN. This takes priority over - `krbsrvname` if present. -*/ -package pq diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/encode.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/encode.go deleted file mode 100644 index 210b1ec34..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/encode.go +++ /dev/null @@ -1,628 +0,0 @@ -package pq - -import ( - "bytes" - "database/sql/driver" - "encoding/binary" - "encoding/hex" - "errors" - "fmt" - "math" - "regexp" - "strconv" - "strings" - "sync" - "time" - - "github.com/lib/pq/oid" -) - -var time2400Regex = regexp.MustCompile(`^(24:00(?::00(?:\.0+)?)?)(?:[Z+-].*)?$`) - -func binaryEncode(parameterStatus *parameterStatus, x interface{}) []byte { - switch v := x.(type) { - case []byte: - return v - default: - return encode(parameterStatus, x, oid.T_unknown) - } -} - -func encode(parameterStatus *parameterStatus, x interface{}, pgtypOid oid.Oid) []byte { - switch v := x.(type) { - case int64: - return strconv.AppendInt(nil, v, 10) - case float64: - return strconv.AppendFloat(nil, v, 'f', -1, 64) - case []byte: - if pgtypOid == oid.T_bytea { - return encodeBytea(parameterStatus.serverVersion, v) - } - - return v - case string: - if pgtypOid == oid.T_bytea { - return encodeBytea(parameterStatus.serverVersion, []byte(v)) - } - - return []byte(v) - case bool: - return strconv.AppendBool(nil, v) - case time.Time: - return formatTs(v) - - default: - errorf("encode: unknown type for %T", v) - } - - panic("not reached") -} - -func decode(parameterStatus *parameterStatus, s []byte, typ oid.Oid, f format) interface{} { - switch f { - case formatBinary: - return binaryDecode(parameterStatus, s, typ) - case formatText: - return textDecode(parameterStatus, s, typ) - default: - panic("not reached") - } -} - -func binaryDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} { - switch typ { - case oid.T_bytea: - return s - case oid.T_int8: - return int64(binary.BigEndian.Uint64(s)) - case oid.T_int4: - return int64(int32(binary.BigEndian.Uint32(s))) - case oid.T_int2: - return int64(int16(binary.BigEndian.Uint16(s))) - case oid.T_uuid: - b, err := decodeUUIDBinary(s) - if err != nil { - panic(err) - } - return b - - default: - errorf("don't know how to decode binary parameter of type %d", uint32(typ)) - } - - panic("not reached") -} - -func textDecode(parameterStatus *parameterStatus, s []byte, typ oid.Oid) interface{} { - switch typ { - case oid.T_char, oid.T_varchar, oid.T_text: - return string(s) - case oid.T_bytea: - b, err := parseBytea(s) - if err != nil { - errorf("%s", err) - } - return b - case oid.T_timestamptz: - return parseTs(parameterStatus.currentLocation, string(s)) - case oid.T_timestamp, oid.T_date: - return parseTs(nil, string(s)) - case oid.T_time: - return mustParse("15:04:05", typ, s) - case oid.T_timetz: - return mustParse("15:04:05-07", typ, s) - case oid.T_bool: - return s[0] == 't' - case oid.T_int8, oid.T_int4, oid.T_int2: - i, err := strconv.ParseInt(string(s), 10, 64) - if err != nil { - errorf("%s", err) - } - return i - case oid.T_float4, oid.T_float8: - // We always use 64 bit parsing, regardless of whether the input text is for - // a float4 or float8, because clients expect float64s for all float datatypes - // and returning a 32-bit parsed float64 produces lossy results. - f, err := strconv.ParseFloat(string(s), 64) - if err != nil { - errorf("%s", err) - } - return f - } - - return s -} - -// appendEncodedText encodes item in text format as required by COPY -// and appends to buf -func appendEncodedText(parameterStatus *parameterStatus, buf []byte, x interface{}) []byte { - switch v := x.(type) { - case int64: - return strconv.AppendInt(buf, v, 10) - case float64: - return strconv.AppendFloat(buf, v, 'f', -1, 64) - case []byte: - encodedBytea := encodeBytea(parameterStatus.serverVersion, v) - return appendEscapedText(buf, string(encodedBytea)) - case string: - return appendEscapedText(buf, v) - case bool: - return strconv.AppendBool(buf, v) - case time.Time: - return append(buf, formatTs(v)...) - case nil: - return append(buf, "\\N"...) - default: - errorf("encode: unknown type for %T", v) - } - - panic("not reached") -} - -func appendEscapedText(buf []byte, text string) []byte { - escapeNeeded := false - startPos := 0 - var c byte - - // check if we need to escape - for i := 0; i < len(text); i++ { - c = text[i] - if c == '\\' || c == '\n' || c == '\r' || c == '\t' { - escapeNeeded = true - startPos = i - break - } - } - if !escapeNeeded { - return append(buf, text...) - } - - // copy till first char to escape, iterate the rest - result := append(buf, text[:startPos]...) - for i := startPos; i < len(text); i++ { - c = text[i] - switch c { - case '\\': - result = append(result, '\\', '\\') - case '\n': - result = append(result, '\\', 'n') - case '\r': - result = append(result, '\\', 'r') - case '\t': - result = append(result, '\\', 't') - default: - result = append(result, c) - } - } - return result -} - -func mustParse(f string, typ oid.Oid, s []byte) time.Time { - str := string(s) - - // Check for a minute and second offset in the timezone. - if typ == oid.T_timestamptz || typ == oid.T_timetz { - for i := 3; i <= 6; i += 3 { - if str[len(str)-i] == ':' { - f += ":00" - continue - } - break - } - } - - // Special case for 24:00 time. - // Unfortunately, golang does not parse 24:00 as a proper time. - // In this case, we want to try "round to the next day", to differentiate. - // As such, we find if the 24:00 time matches at the beginning; if so, - // we default it back to 00:00 but add a day later. - var is2400Time bool - switch typ { - case oid.T_timetz, oid.T_time: - if matches := time2400Regex.FindStringSubmatch(str); matches != nil { - // Concatenate timezone information at the back. - str = "00:00:00" + str[len(matches[1]):] - is2400Time = true - } - } - t, err := time.Parse(f, str) - if err != nil { - errorf("decode: %s", err) - } - if is2400Time { - t = t.Add(24 * time.Hour) - } - return t -} - -var errInvalidTimestamp = errors.New("invalid timestamp") - -type timestampParser struct { - err error -} - -func (p *timestampParser) expect(str string, char byte, pos int) { - if p.err != nil { - return - } - if pos+1 > len(str) { - p.err = errInvalidTimestamp - return - } - if c := str[pos]; c != char && p.err == nil { - p.err = fmt.Errorf("expected '%v' at position %v; got '%v'", char, pos, c) - } -} - -func (p *timestampParser) mustAtoi(str string, begin int, end int) int { - if p.err != nil { - return 0 - } - if begin < 0 || end < 0 || begin > end || end > len(str) { - p.err = errInvalidTimestamp - return 0 - } - result, err := strconv.Atoi(str[begin:end]) - if err != nil { - if p.err == nil { - p.err = fmt.Errorf("expected number; got '%v'", str) - } - return 0 - } - return result -} - -// The location cache caches the time zones typically used by the client. -type locationCache struct { - cache map[int]*time.Location - lock sync.Mutex -} - -// All connections share the same list of timezones. Benchmarking shows that -// about 5% speed could be gained by putting the cache in the connection and -// losing the mutex, at the cost of a small amount of memory and a somewhat -// significant increase in code complexity. -var globalLocationCache = newLocationCache() - -func newLocationCache() *locationCache { - return &locationCache{cache: make(map[int]*time.Location)} -} - -// Returns the cached timezone for the specified offset, creating and caching -// it if necessary. -func (c *locationCache) getLocation(offset int) *time.Location { - c.lock.Lock() - defer c.lock.Unlock() - - location, ok := c.cache[offset] - if !ok { - location = time.FixedZone("", offset) - c.cache[offset] = location - } - - return location -} - -var infinityTsEnabled = false -var infinityTsNegative time.Time -var infinityTsPositive time.Time - -const ( - infinityTsEnabledAlready = "pq: infinity timestamp enabled already" - infinityTsNegativeMustBeSmaller = "pq: infinity timestamp: negative value must be smaller (before) than positive" -) - -// EnableInfinityTs controls the handling of Postgres' "-infinity" and -// "infinity" "timestamp"s. -// -// If EnableInfinityTs is not called, "-infinity" and "infinity" will return -// []byte("-infinity") and []byte("infinity") respectively, and potentially -// cause error "sql: Scan error on column index 0: unsupported driver -> Scan -// pair: []uint8 -> *time.Time", when scanning into a time.Time value. -// -// Once EnableInfinityTs has been called, all connections created using this -// driver will decode Postgres' "-infinity" and "infinity" for "timestamp", -// "timestamp with time zone" and "date" types to the predefined minimum and -// maximum times, respectively. When encoding time.Time values, any time which -// equals or precedes the predefined minimum time will be encoded to -// "-infinity". Any values at or past the maximum time will similarly be -// encoded to "infinity". -// -// If EnableInfinityTs is called with negative >= positive, it will panic. -// Calling EnableInfinityTs after a connection has been established results in -// undefined behavior. If EnableInfinityTs is called more than once, it will -// panic. -func EnableInfinityTs(negative time.Time, positive time.Time) { - if infinityTsEnabled { - panic(infinityTsEnabledAlready) - } - if !negative.Before(positive) { - panic(infinityTsNegativeMustBeSmaller) - } - infinityTsEnabled = true - infinityTsNegative = negative - infinityTsPositive = positive -} - -/* - * Testing might want to toggle infinityTsEnabled - */ -func disableInfinityTs() { - infinityTsEnabled = false -} - -// This is a time function specific to the Postgres default DateStyle -// setting ("ISO, MDY"), the only one we currently support. This -// accounts for the discrepancies between the parsing available with -// time.Parse and the Postgres date formatting quirks. -func parseTs(currentLocation *time.Location, str string) interface{} { - switch str { - case "-infinity": - if infinityTsEnabled { - return infinityTsNegative - } - return []byte(str) - case "infinity": - if infinityTsEnabled { - return infinityTsPositive - } - return []byte(str) - } - t, err := ParseTimestamp(currentLocation, str) - if err != nil { - panic(err) - } - return t -} - -// ParseTimestamp parses Postgres' text format. It returns a time.Time in -// currentLocation iff that time's offset agrees with the offset sent from the -// Postgres server. Otherwise, ParseTimestamp returns a time.Time with the -// fixed offset offset provided by the Postgres server. -func ParseTimestamp(currentLocation *time.Location, str string) (time.Time, error) { - p := timestampParser{} - - monSep := strings.IndexRune(str, '-') - // this is Gregorian year, not ISO Year - // In Gregorian system, the year 1 BC is followed by AD 1 - year := p.mustAtoi(str, 0, monSep) - daySep := monSep + 3 - month := p.mustAtoi(str, monSep+1, daySep) - p.expect(str, '-', daySep) - timeSep := daySep + 3 - day := p.mustAtoi(str, daySep+1, timeSep) - - minLen := monSep + len("01-01") + 1 - - isBC := strings.HasSuffix(str, " BC") - if isBC { - minLen += 3 - } - - var hour, minute, second int - if len(str) > minLen { - p.expect(str, ' ', timeSep) - minSep := timeSep + 3 - p.expect(str, ':', minSep) - hour = p.mustAtoi(str, timeSep+1, minSep) - secSep := minSep + 3 - p.expect(str, ':', secSep) - minute = p.mustAtoi(str, minSep+1, secSep) - secEnd := secSep + 3 - second = p.mustAtoi(str, secSep+1, secEnd) - } - remainderIdx := monSep + len("01-01 00:00:00") + 1 - // Three optional (but ordered) sections follow: the - // fractional seconds, the time zone offset, and the BC - // designation. We set them up here and adjust the other - // offsets if the preceding sections exist. - - nanoSec := 0 - tzOff := 0 - - if remainderIdx < len(str) && str[remainderIdx] == '.' { - fracStart := remainderIdx + 1 - fracOff := strings.IndexAny(str[fracStart:], "-+ ") - if fracOff < 0 { - fracOff = len(str) - fracStart - } - fracSec := p.mustAtoi(str, fracStart, fracStart+fracOff) - nanoSec = fracSec * (1000000000 / int(math.Pow(10, float64(fracOff)))) - - remainderIdx += fracOff + 1 - } - if tzStart := remainderIdx; tzStart < len(str) && (str[tzStart] == '-' || str[tzStart] == '+') { - // time zone separator is always '-' or '+' (UTC is +00) - var tzSign int - switch c := str[tzStart]; c { - case '-': - tzSign = -1 - case '+': - tzSign = +1 - default: - return time.Time{}, fmt.Errorf("expected '-' or '+' at position %v; got %v", tzStart, c) - } - tzHours := p.mustAtoi(str, tzStart+1, tzStart+3) - remainderIdx += 3 - var tzMin, tzSec int - if remainderIdx < len(str) && str[remainderIdx] == ':' { - tzMin = p.mustAtoi(str, remainderIdx+1, remainderIdx+3) - remainderIdx += 3 - } - if remainderIdx < len(str) && str[remainderIdx] == ':' { - tzSec = p.mustAtoi(str, remainderIdx+1, remainderIdx+3) - remainderIdx += 3 - } - tzOff = tzSign * ((tzHours * 60 * 60) + (tzMin * 60) + tzSec) - } - var isoYear int - - if isBC { - isoYear = 1 - year - remainderIdx += 3 - } else { - isoYear = year - } - if remainderIdx < len(str) { - return time.Time{}, fmt.Errorf("expected end of input, got %v", str[remainderIdx:]) - } - t := time.Date(isoYear, time.Month(month), day, - hour, minute, second, nanoSec, - globalLocationCache.getLocation(tzOff)) - - if currentLocation != nil { - // Set the location of the returned Time based on the session's - // TimeZone value, but only if the local time zone database agrees with - // the remote database on the offset. - lt := t.In(currentLocation) - _, newOff := lt.Zone() - if newOff == tzOff { - t = lt - } - } - - return t, p.err -} - -// formatTs formats t into a format postgres understands. -func formatTs(t time.Time) []byte { - if infinityTsEnabled { - // t <= -infinity : ! (t > -infinity) - if !t.After(infinityTsNegative) { - return []byte("-infinity") - } - // t >= infinity : ! (!t < infinity) - if !t.Before(infinityTsPositive) { - return []byte("infinity") - } - } - return FormatTimestamp(t) -} - -// FormatTimestamp formats t into Postgres' text format for timestamps. -func FormatTimestamp(t time.Time) []byte { - // Need to send dates before 0001 A.D. with " BC" suffix, instead of the - // minus sign preferred by Go. - // Beware, "0000" in ISO is "1 BC", "-0001" is "2 BC" and so on - bc := false - if t.Year() <= 0 { - // flip year sign, and add 1, e.g: "0" will be "1", and "-10" will be "11" - t = t.AddDate((-t.Year())*2+1, 0, 0) - bc = true - } - b := []byte(t.Format("2006-01-02 15:04:05.999999999Z07:00")) - - _, offset := t.Zone() - offset %= 60 - if offset != 0 { - // RFC3339Nano already printed the minus sign - if offset < 0 { - offset = -offset - } - - b = append(b, ':') - if offset < 10 { - b = append(b, '0') - } - b = strconv.AppendInt(b, int64(offset), 10) - } - - if bc { - b = append(b, " BC"...) - } - return b -} - -// Parse a bytea value received from the server. Both "hex" and the legacy -// "escape" format are supported. -func parseBytea(s []byte) (result []byte, err error) { - if len(s) >= 2 && bytes.Equal(s[:2], []byte("\\x")) { - // bytea_output = hex - s = s[2:] // trim off leading "\\x" - result = make([]byte, hex.DecodedLen(len(s))) - _, err := hex.Decode(result, s) - if err != nil { - return nil, err - } - } else { - // bytea_output = escape - for len(s) > 0 { - if s[0] == '\\' { - // escaped '\\' - if len(s) >= 2 && s[1] == '\\' { - result = append(result, '\\') - s = s[2:] - continue - } - - // '\\' followed by an octal number - if len(s) < 4 { - return nil, fmt.Errorf("invalid bytea sequence %v", s) - } - r, err := strconv.ParseUint(string(s[1:4]), 8, 8) - if err != nil { - return nil, fmt.Errorf("could not parse bytea value: %s", err.Error()) - } - result = append(result, byte(r)) - s = s[4:] - } else { - // We hit an unescaped, raw byte. Try to read in as many as - // possible in one go. - i := bytes.IndexByte(s, '\\') - if i == -1 { - result = append(result, s...) - break - } - result = append(result, s[:i]...) - s = s[i:] - } - } - } - - return result, nil -} - -func encodeBytea(serverVersion int, v []byte) (result []byte) { - if serverVersion >= 90000 { - // Use the hex format if we know that the server supports it - result = make([]byte, 2+hex.EncodedLen(len(v))) - result[0] = '\\' - result[1] = 'x' - hex.Encode(result[2:], v) - } else { - // .. or resort to "escape" - for _, b := range v { - if b == '\\' { - result = append(result, '\\', '\\') - } else if b < 0x20 || b > 0x7e { - result = append(result, []byte(fmt.Sprintf("\\%03o", b))...) - } else { - result = append(result, b) - } - } - } - - return result -} - -// NullTime represents a time.Time that may be null. NullTime implements the -// sql.Scanner interface so it can be used as a scan destination, similar to -// sql.NullString. -type NullTime struct { - Time time.Time - Valid bool // Valid is true if Time is not NULL -} - -// Scan implements the Scanner interface. -func (nt *NullTime) Scan(value interface{}) error { - nt.Time, nt.Valid = value.(time.Time) - return nil -} - -// Value implements the driver Valuer interface. -func (nt NullTime) Value() (driver.Value, error) { - if !nt.Valid { - return nil, nil - } - return nt.Time, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/encode_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/encode_test.go deleted file mode 100644 index bffa83868..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/encode_test.go +++ /dev/null @@ -1,849 +0,0 @@ -package pq - -import ( - "bytes" - "database/sql" - "fmt" - "regexp" - "testing" - "time" - - "github.com/lib/pq/oid" -) - -func TestScanTimestamp(t *testing.T) { - var nt NullTime - tn := time.Now() - nt.Scan(tn) - if !nt.Valid { - t.Errorf("Expected Valid=false") - } - if nt.Time != tn { - t.Errorf("Time value mismatch") - } -} - -func TestScanNilTimestamp(t *testing.T) { - var nt NullTime - nt.Scan(nil) - if nt.Valid { - t.Errorf("Expected Valid=false") - } -} - -var timeTests = []struct { - str string - timeval time.Time -}{ - {"22001-02-03", time.Date(22001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))}, - {"2001-02-03", time.Date(2001, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))}, - {"0001-12-31 BC", time.Date(0, time.December, 31, 0, 0, 0, 0, time.FixedZone("", 0))}, - {"2001-02-03 BC", time.Date(-2000, time.February, 3, 0, 0, 0, 0, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06", time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.000001", time.Date(2001, time.February, 3, 4, 5, 6, 1000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.00001", time.Date(2001, time.February, 3, 4, 5, 6, 10000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.0001", time.Date(2001, time.February, 3, 4, 5, 6, 100000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.001", time.Date(2001, time.February, 3, 4, 5, 6, 1000000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.01", time.Date(2001, time.February, 3, 4, 5, 6, 10000000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.1", time.Date(2001, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.12", time.Date(2001, time.February, 3, 4, 5, 6, 120000000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.123", time.Date(2001, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.1234", time.Date(2001, time.February, 3, 4, 5, 6, 123400000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.12345", time.Date(2001, time.February, 3, 4, 5, 6, 123450000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.123456", time.Date(2001, time.February, 3, 4, 5, 6, 123456000, time.FixedZone("", 0))}, - {"2001-02-03 04:05:06.123-07", time.Date(2001, time.February, 3, 4, 5, 6, 123000000, - time.FixedZone("", -7*60*60))}, - {"2001-02-03 04:05:06-07", time.Date(2001, time.February, 3, 4, 5, 6, 0, - time.FixedZone("", -7*60*60))}, - {"2001-02-03 04:05:06-07:42", time.Date(2001, time.February, 3, 4, 5, 6, 0, - time.FixedZone("", -(7*60*60+42*60)))}, - {"2001-02-03 04:05:06-07:30:09", time.Date(2001, time.February, 3, 4, 5, 6, 0, - time.FixedZone("", -(7*60*60+30*60+9)))}, - {"2001-02-03 04:05:06+07:30:09", time.Date(2001, time.February, 3, 4, 5, 6, 0, - time.FixedZone("", +(7*60*60+30*60+9)))}, - {"2001-02-03 04:05:06+07", time.Date(2001, time.February, 3, 4, 5, 6, 0, - time.FixedZone("", 7*60*60))}, - {"0011-02-03 04:05:06 BC", time.Date(-10, time.February, 3, 4, 5, 6, 0, time.FixedZone("", 0))}, - {"0011-02-03 04:05:06.123 BC", time.Date(-10, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, - {"0011-02-03 04:05:06.123-07 BC", time.Date(-10, time.February, 3, 4, 5, 6, 123000000, - time.FixedZone("", -7*60*60))}, - {"0001-02-03 04:05:06.123", time.Date(1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, - {"0001-02-03 04:05:06.123 BC", time.Date(1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0)).AddDate(-1, 0, 0)}, - {"0001-02-03 04:05:06.123 BC", time.Date(0, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, - {"0002-02-03 04:05:06.123 BC", time.Date(0, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0)).AddDate(-1, 0, 0)}, - {"0002-02-03 04:05:06.123 BC", time.Date(-1, time.February, 3, 4, 5, 6, 123000000, time.FixedZone("", 0))}, - {"12345-02-03 04:05:06.1", time.Date(12345, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))}, - {"123456-02-03 04:05:06.1", time.Date(123456, time.February, 3, 4, 5, 6, 100000000, time.FixedZone("", 0))}, -} - -// Test that parsing the string results in the expected value. -func TestParseTs(t *testing.T) { - for i, tt := range timeTests { - val, err := ParseTimestamp(nil, tt.str) - if err != nil { - t.Errorf("%d: got error: %v", i, err) - } else if val.String() != tt.timeval.String() { - t.Errorf("%d: expected to parse %q into %q; got %q", - i, tt.str, tt.timeval, val) - } - } -} - -var timeErrorTests = []string{ - "BC", - " BC", - "2001", - "2001-2-03", - "2001-02-3", - "2001-02-03 ", - "2001-02-03 B", - "2001-02-03 04", - "2001-02-03 04:", - "2001-02-03 04:05", - "2001-02-03 04:05 B", - "2001-02-03 04:05 BC", - "2001-02-03 04:05:", - "2001-02-03 04:05:6", - "2001-02-03 04:05:06 B", - "2001-02-03 04:05:06BC", - "2001-02-03 04:05:06.123 B", -} - -// Test that parsing the string results in an error. -func TestParseTsErrors(t *testing.T) { - for i, tt := range timeErrorTests { - _, err := ParseTimestamp(nil, tt) - if err == nil { - t.Errorf("%d: expected an error from parsing: %v", i, tt) - } - } -} - -// Now test that sending the value into the database and parsing it back -// returns the same time.Time value. -func TestEncodeAndParseTs(t *testing.T) { - db, err := openTestConnConninfo("timezone='Etc/UTC'") - if err != nil { - t.Fatal(err) - } - defer db.Close() - - for i, tt := range timeTests { - var dbstr string - err = db.QueryRow("SELECT ($1::timestamptz)::text", tt.timeval).Scan(&dbstr) - if err != nil { - t.Errorf("%d: could not send value %q to the database: %s", i, tt.timeval, err) - continue - } - - val, err := ParseTimestamp(nil, dbstr) - if err != nil { - t.Errorf("%d: could not parse value %q: %s", i, dbstr, err) - continue - } - val = val.In(tt.timeval.Location()) - if val.String() != tt.timeval.String() { - t.Errorf("%d: expected to parse %q into %q; got %q", i, dbstr, tt.timeval, val) - } - } -} - -var formatTimeTests = []struct { - time time.Time - expected string -}{ - {time.Time{}, "0001-01-01 00:00:00Z"}, - {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "2001-02-03 04:05:06.123456789Z"}, - {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "2001-02-03 04:05:06.123456789+02:00"}, - {time.Date(2001, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "2001-02-03 04:05:06.123456789-06:00"}, - {time.Date(2001, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "2001-02-03 04:05:06-07:30:09"}, - - {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03 04:05:06.123456789Z"}, - {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03 04:05:06.123456789+02:00"}, - {time.Date(1, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03 04:05:06.123456789-06:00"}, - - {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 0)), "0001-02-03 04:05:06.123456789Z BC"}, - {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", 2*60*60)), "0001-02-03 04:05:06.123456789+02:00 BC"}, - {time.Date(0, time.February, 3, 4, 5, 6, 123456789, time.FixedZone("", -6*60*60)), "0001-02-03 04:05:06.123456789-06:00 BC"}, - - {time.Date(1, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03 04:05:06-07:30:09"}, - {time.Date(0, time.February, 3, 4, 5, 6, 0, time.FixedZone("", -(7*60*60+30*60+9))), "0001-02-03 04:05:06-07:30:09 BC"}, -} - -func TestFormatTs(t *testing.T) { - for i, tt := range formatTimeTests { - val := string(formatTs(tt.time)) - if val != tt.expected { - t.Errorf("%d: incorrect time format %q, want %q", i, val, tt.expected) - } - } -} - -func TestFormatTsBackend(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - var str string - err := db.QueryRow("SELECT '2001-02-03T04:05:06.007-08:09:10'::time::text").Scan(&str) - if err == nil { - t.Fatalf("PostgreSQL is accepting an ISO timestamp input for time") - } - - for i, tt := range formatTimeTests { - for _, typ := range []string{"date", "time", "timetz", "timestamp", "timestamptz"} { - err = db.QueryRow("SELECT $1::"+typ+"::text", tt.time).Scan(&str) - if err != nil { - t.Errorf("%d: incorrect time format for %v on the backend: %v", i, typ, err) - } - } - } -} - -func TestTimeWithoutTimezone(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - tx, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer tx.Rollback() - - for _, tc := range []struct { - refTime string - expectedTime time.Time - }{ - {"11:59:59", time.Date(0, 1, 1, 11, 59, 59, 0, time.UTC)}, - {"24:00", time.Date(0, 1, 2, 0, 0, 0, 0, time.UTC)}, - {"24:00:00", time.Date(0, 1, 2, 0, 0, 0, 0, time.UTC)}, - {"24:00:00.0", time.Date(0, 1, 2, 0, 0, 0, 0, time.UTC)}, - {"24:00:00.000000", time.Date(0, 1, 2, 0, 0, 0, 0, time.UTC)}, - } { - t.Run( - fmt.Sprintf("%s => %s", tc.refTime, tc.expectedTime.Format(time.RFC3339)), - func(t *testing.T) { - var gotTime time.Time - row := tx.QueryRow("select $1::time", tc.refTime) - err = row.Scan(&gotTime) - if err != nil { - t.Fatal(err) - } - - if !tc.expectedTime.Equal(gotTime) { - t.Errorf("timestamps not equal: %s != %s", tc.expectedTime, gotTime) - } - }, - ) - } -} - -func TestTimeWithTimezone(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - tx, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer tx.Rollback() - - for _, tc := range []struct { - refTime string - expectedTime time.Time - }{ - {"11:59:59+00:00", time.Date(0, 1, 1, 11, 59, 59, 0, time.UTC)}, - {"11:59:59+04:00", time.Date(0, 1, 1, 11, 59, 59, 0, time.FixedZone("+04", 4*60*60))}, - {"11:59:59+04:01:02", time.Date(0, 1, 1, 11, 59, 59, 0, time.FixedZone("+04:01:02", 4*60*60+1*60+2))}, - {"11:59:59-04:01:02", time.Date(0, 1, 1, 11, 59, 59, 0, time.FixedZone("-04:01:02", -(4*60*60+1*60+2)))}, - {"24:00+00", time.Date(0, 1, 2, 0, 0, 0, 0, time.UTC)}, - {"24:00Z", time.Date(0, 1, 2, 0, 0, 0, 0, time.UTC)}, - {"24:00-04:00", time.Date(0, 1, 2, 0, 0, 0, 0, time.FixedZone("-04", -4*60*60))}, - {"24:00:00+00", time.Date(0, 1, 2, 0, 0, 0, 0, time.UTC)}, - {"24:00:00.0+00", time.Date(0, 1, 2, 0, 0, 0, 0, time.UTC)}, - {"24:00:00.000000+00", time.Date(0, 1, 2, 0, 0, 0, 0, time.UTC)}, - } { - t.Run( - fmt.Sprintf("%s => %s", tc.refTime, tc.expectedTime.Format(time.RFC3339)), - func(t *testing.T) { - var gotTime time.Time - row := tx.QueryRow("select $1::timetz", tc.refTime) - err = row.Scan(&gotTime) - if err != nil { - t.Fatal(err) - } - - if !tc.expectedTime.Equal(gotTime) { - t.Errorf("timestamps not equal: %s != %s", tc.expectedTime, gotTime) - } - }, - ) - } -} - -func TestTimestampWithTimeZone(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - tx, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer tx.Rollback() - - // try several different locations, all included in Go's zoneinfo.zip - for _, locName := range []string{ - "UTC", - "America/Chicago", - "America/New_York", - "Australia/Darwin", - "Australia/Perth", - } { - loc, err := time.LoadLocation(locName) - if err != nil { - t.Logf("Could not load time zone %s - skipping", locName) - continue - } - - // Postgres timestamps have a resolution of 1 microsecond, so don't - // use the full range of the Nanosecond argument - refTime := time.Date(2012, 11, 6, 10, 23, 42, 123456000, loc) - - for _, pgTimeZone := range []string{"US/Eastern", "Australia/Darwin"} { - // Switch Postgres's timezone to test different output timestamp formats - _, err = tx.Exec(fmt.Sprintf("set time zone '%s'", pgTimeZone)) - if err != nil { - t.Fatal(err) - } - - var gotTime time.Time - row := tx.QueryRow("select $1::timestamp with time zone", refTime) - err = row.Scan(&gotTime) - if err != nil { - t.Fatal(err) - } - - if !refTime.Equal(gotTime) { - t.Errorf("timestamps not equal: %s != %s", refTime, gotTime) - } - - // check that the time zone is set correctly based on TimeZone - pgLoc, err := time.LoadLocation(pgTimeZone) - if err != nil { - t.Logf("Could not load time zone %s - skipping", pgLoc) - continue - } - translated := refTime.In(pgLoc) - if translated.String() != gotTime.String() { - t.Errorf("timestamps not equal: %s != %s", translated, gotTime) - } - } - } -} - -func TestTimestampWithOutTimezone(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - test := func(ts, pgts string) { - r, err := db.Query("SELECT $1::timestamp", pgts) - if err != nil { - t.Fatalf("Could not run query: %v", err) - } - - if !r.Next() { - t.Fatal("Expected at least one row") - } - - var result time.Time - err = r.Scan(&result) - if err != nil { - t.Fatalf("Did not expect error scanning row: %v", err) - } - - expected, err := time.Parse(time.RFC3339, ts) - if err != nil { - t.Fatalf("Could not parse test time literal: %v", err) - } - - if !result.Equal(expected) { - t.Fatalf("Expected time to match %v: got mismatch %v", - expected, result) - } - - if r.Next() { - t.Fatal("Expected only one row") - } - } - - test("2000-01-01T00:00:00Z", "2000-01-01T00:00:00") - - // Test higher precision time - test("2013-01-04T20:14:58.80033Z", "2013-01-04 20:14:58.80033") -} - -func TestInfinityTimestamp(t *testing.T) { - db := openTestConn(t) - defer db.Close() - var err error - var resultT time.Time - - expectedErrorStrRegexp := regexp.MustCompile( - `^sql: Scan error on column index 0(, name "timestamp(tz)?"|): unsupported`) - - type testCases []struct { - Query string - Param string - ExpectedErrorStrRegexp *regexp.Regexp - ExpectedVal interface{} - } - tc := testCases{ - {"SELECT $1::timestamp", "-infinity", expectedErrorStrRegexp, "-infinity"}, - {"SELECT $1::timestamptz", "-infinity", expectedErrorStrRegexp, "-infinity"}, - {"SELECT $1::timestamp", "infinity", expectedErrorStrRegexp, "infinity"}, - {"SELECT $1::timestamptz", "infinity", expectedErrorStrRegexp, "infinity"}, - } - // try to assert []byte to time.Time - for _, q := range tc { - err = db.QueryRow(q.Query, q.Param).Scan(&resultT) - if err == nil || !q.ExpectedErrorStrRegexp.MatchString(err.Error()) { - t.Errorf("Scanning -/+infinity, expected error to match regexp %q, got %q", - q.ExpectedErrorStrRegexp, err) - } - } - // yield []byte - for _, q := range tc { - var resultI interface{} - err = db.QueryRow(q.Query, q.Param).Scan(&resultI) - if err != nil { - t.Errorf("Scanning -/+infinity, expected no error, got %q", err) - } - result, ok := resultI.([]byte) - if !ok { - t.Errorf("Scanning -/+infinity, expected []byte, got %#v", resultI) - } - if string(result) != q.ExpectedVal { - t.Errorf("Scanning -/+infinity, expected %q, got %q", q.ExpectedVal, result) - } - } - - y1500 := time.Date(1500, time.January, 1, 0, 0, 0, 0, time.UTC) - y2500 := time.Date(2500, time.January, 1, 0, 0, 0, 0, time.UTC) - EnableInfinityTs(y1500, y2500) - - err = db.QueryRow("SELECT $1::timestamp", "infinity").Scan(&resultT) - if err != nil { - t.Errorf("Scanning infinity, expected no error, got %q", err) - } - if !resultT.Equal(y2500) { - t.Errorf("Scanning infinity, expected %q, got %q", y2500, resultT) - } - - err = db.QueryRow("SELECT $1::timestamptz", "infinity").Scan(&resultT) - if err != nil { - t.Errorf("Scanning infinity, expected no error, got %q", err) - } - if !resultT.Equal(y2500) { - t.Errorf("Scanning Infinity, expected time %q, got %q", y2500, resultT.String()) - } - - err = db.QueryRow("SELECT $1::timestamp", "-infinity").Scan(&resultT) - if err != nil { - t.Errorf("Scanning -infinity, expected no error, got %q", err) - } - if !resultT.Equal(y1500) { - t.Errorf("Scanning -infinity, expected time %q, got %q", y1500, resultT.String()) - } - - err = db.QueryRow("SELECT $1::timestamptz", "-infinity").Scan(&resultT) - if err != nil { - t.Errorf("Scanning -infinity, expected no error, got %q", err) - } - if !resultT.Equal(y1500) { - t.Errorf("Scanning -infinity, expected time %q, got %q", y1500, resultT.String()) - } - - ym1500 := time.Date(-1500, time.January, 1, 0, 0, 0, 0, time.UTC) - y11500 := time.Date(11500, time.January, 1, 0, 0, 0, 0, time.UTC) - var s string - err = db.QueryRow("SELECT $1::timestamp::text", ym1500).Scan(&s) - if err != nil { - t.Errorf("Encoding -infinity, expected no error, got %q", err) - } - if s != "-infinity" { - t.Errorf("Encoding -infinity, expected %q, got %q", "-infinity", s) - } - err = db.QueryRow("SELECT $1::timestamptz::text", ym1500).Scan(&s) - if err != nil { - t.Errorf("Encoding -infinity, expected no error, got %q", err) - } - if s != "-infinity" { - t.Errorf("Encoding -infinity, expected %q, got %q", "-infinity", s) - } - - err = db.QueryRow("SELECT $1::timestamp::text", y11500).Scan(&s) - if err != nil { - t.Errorf("Encoding infinity, expected no error, got %q", err) - } - if s != "infinity" { - t.Errorf("Encoding infinity, expected %q, got %q", "infinity", s) - } - err = db.QueryRow("SELECT $1::timestamptz::text", y11500).Scan(&s) - if err != nil { - t.Errorf("Encoding infinity, expected no error, got %q", err) - } - if s != "infinity" { - t.Errorf("Encoding infinity, expected %q, got %q", "infinity", s) - } - - disableInfinityTs() - - var panicErrorString string - func() { - defer func() { - panicErrorString, _ = recover().(string) - }() - EnableInfinityTs(y2500, y1500) - }() - if panicErrorString != infinityTsNegativeMustBeSmaller { - t.Errorf("Expected error, %q, got %q", infinityTsNegativeMustBeSmaller, panicErrorString) - } -} - -func TestStringWithNul(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - hello0world := string("hello\x00world") - _, err := db.Query("SELECT $1::text", &hello0world) - if err == nil { - t.Fatal("Postgres accepts a string with nul in it; " + - "injection attacks may be plausible") - } -} - -func TestByteSliceToText(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - b := []byte("hello world") - row := db.QueryRow("SELECT $1::text", b) - - var result []byte - err := row.Scan(&result) - if err != nil { - t.Fatal(err) - } - - if string(result) != string(b) { - t.Fatalf("expected %v but got %v", b, result) - } -} - -func TestStringToBytea(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - b := "hello world" - row := db.QueryRow("SELECT $1::bytea", b) - - var result []byte - err := row.Scan(&result) - if err != nil { - t.Fatal(err) - } - - if !bytes.Equal(result, []byte(b)) { - t.Fatalf("expected %v but got %v", b, result) - } -} - -func TestTextByteSliceToUUID(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - b := []byte("a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11") - row := db.QueryRow("SELECT $1::uuid", b) - - var result string - err := row.Scan(&result) - if forceBinaryParameters() { - pqErr := err.(*Error) - if pqErr == nil { - t.Errorf("Expected to get error") - } else if pqErr.Code != "22P03" { - t.Fatalf("Expected to get invalid binary encoding error (22P03), got %s", pqErr.Code) - } - } else { - if err != nil { - t.Fatal(err) - } - - if result != string(b) { - t.Fatalf("expected %v but got %v", b, result) - } - } -} - -func TestBinaryByteSlicetoUUID(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - b := []byte{'\xa0', '\xee', '\xbc', '\x99', - '\x9c', '\x0b', - '\x4e', '\xf8', - '\xbb', '\x00', '\x6b', - '\xb9', '\xbd', '\x38', '\x0a', '\x11'} - row := db.QueryRow("SELECT $1::uuid", b) - - var result string - err := row.Scan(&result) - if forceBinaryParameters() { - if err != nil { - t.Fatal(err) - } - - if result != string("a0eebc99-9c0b-4ef8-bb00-6bb9bd380a11") { - t.Fatalf("expected %v but got %v", b, result) - } - } else { - pqErr := err.(*Error) - if pqErr == nil { - t.Errorf("Expected to get error") - } else if pqErr.Code != "22021" { - t.Fatalf("Expected to get invalid byte sequence for encoding error (22021), got %s", pqErr.Code) - } - } -} - -func TestStringToUUID(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - s := "a0eebc99-9c0b-4ef8-bb00-6bb9bd380a11" - row := db.QueryRow("SELECT $1::uuid", s) - - var result string - err := row.Scan(&result) - if err != nil { - t.Fatal(err) - } - - if result != s { - t.Fatalf("expected %v but got %v", s, result) - } -} - -func TestTextByteSliceToInt(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - expected := 12345678 - b := []byte(fmt.Sprintf("%d", expected)) - row := db.QueryRow("SELECT $1::int", b) - - var result int - err := row.Scan(&result) - if forceBinaryParameters() { - pqErr := err.(*Error) - if pqErr == nil { - t.Errorf("Expected to get error") - } else if pqErr.Code != "22P03" { - t.Fatalf("Expected to get invalid binary encoding error (22P03), got %s", pqErr.Code) - } - } else { - if err != nil { - t.Fatal(err) - } - if result != expected { - t.Fatalf("expected %v but got %v", expected, result) - } - } -} - -func TestBinaryByteSliceToInt(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - expected := 12345678 - b := []byte{'\x00', '\xbc', '\x61', '\x4e'} - row := db.QueryRow("SELECT $1::int", b) - - var result int - err := row.Scan(&result) - if forceBinaryParameters() { - if err != nil { - t.Fatal(err) - } - if result != expected { - t.Fatalf("expected %v but got %v", expected, result) - } - } else { - pqErr := err.(*Error) - if pqErr == nil { - t.Errorf("Expected to get error") - } else if pqErr.Code != "22021" { - t.Fatalf("Expected to get invalid byte sequence for encoding error (22021), got %s", pqErr.Code) - } - } -} - -func TestTextDecodeIntoString(t *testing.T) { - input := []byte("hello world") - want := string(input) - for _, typ := range []oid.Oid{oid.T_char, oid.T_varchar, oid.T_text} { - got := decode(¶meterStatus{}, input, typ, formatText) - if got != want { - t.Errorf("invalid string decoding output for %T(%+v), got %v but expected %v", typ, typ, got, want) - } - } -} - -func TestByteaOutputFormatEncoding(t *testing.T) { - input := []byte("\\x\x00\x01\x02\xFF\xFEabcdefg0123") - want := []byte("\\x5c78000102fffe6162636465666730313233") - got := encode(¶meterStatus{serverVersion: 90000}, input, oid.T_bytea) - if !bytes.Equal(want, got) { - t.Errorf("invalid hex bytea output, got %v but expected %v", got, want) - } - - want = []byte("\\\\x\\000\\001\\002\\377\\376abcdefg0123") - got = encode(¶meterStatus{serverVersion: 84000}, input, oid.T_bytea) - if !bytes.Equal(want, got) { - t.Errorf("invalid escape bytea output, got %v but expected %v", got, want) - } -} - -func TestByteaOutputFormats(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - if getServerVersion(t, db) < 90000 { - // skip - return - } - - testByteaOutputFormat := func(f string, usePrepared bool) { - expectedData := []byte("\x5c\x78\x00\xff\x61\x62\x63\x01\x08") - sqlQuery := "SELECT decode('5c7800ff6162630108', 'hex')" - - var data []byte - - // use a txn to avoid relying on getting the same connection - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - defer txn.Rollback() - - _, err = txn.Exec("SET LOCAL bytea_output TO " + f) - if err != nil { - t.Fatal(err) - } - var rows *sql.Rows - var stmt *sql.Stmt - if usePrepared { - stmt, err = txn.Prepare(sqlQuery) - if err != nil { - t.Fatal(err) - } - rows, err = stmt.Query() - } else { - // use Query; QueryRow would hide the actual error - rows, err = txn.Query(sqlQuery) - } - if err != nil { - t.Fatal(err) - } - if !rows.Next() { - if rows.Err() != nil { - t.Fatal(rows.Err()) - } - t.Fatal("shouldn't happen") - } - err = rows.Scan(&data) - if err != nil { - t.Fatal(err) - } - err = rows.Close() - if err != nil { - t.Fatal(err) - } - if stmt != nil { - err = stmt.Close() - if err != nil { - t.Fatal(err) - } - } - if !bytes.Equal(data, expectedData) { - t.Errorf("unexpected bytea value %v for format %s; expected %v", data, f, expectedData) - } - } - - testByteaOutputFormat("hex", false) - testByteaOutputFormat("escape", false) - testByteaOutputFormat("hex", true) - testByteaOutputFormat("escape", true) -} - -func TestAppendEncodedText(t *testing.T) { - var buf []byte - - buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, int64(10)) - buf = append(buf, '\t') - buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, 42.0000000001) - buf = append(buf, '\t') - buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, "hello\tworld") - buf = append(buf, '\t') - buf = appendEncodedText(¶meterStatus{serverVersion: 90000}, buf, []byte{0, 128, 255}) - - if string(buf) != "10\t42.0000000001\thello\\tworld\t\\\\x0080ff" { - t.Fatal(string(buf)) - } -} - -func TestAppendEscapedText(t *testing.T) { - if esc := appendEscapedText(nil, "hallo\tescape"); string(esc) != "hallo\\tescape" { - t.Fatal(string(esc)) - } - if esc := appendEscapedText(nil, "hallo\\tescape\n"); string(esc) != "hallo\\\\tescape\\n" { - t.Fatal(string(esc)) - } - if esc := appendEscapedText(nil, "\n\r\t\f"); string(esc) != "\\n\\r\\t\f" { - t.Fatal(string(esc)) - } -} - -func TestAppendEscapedTextExistingBuffer(t *testing.T) { - buf := []byte("123\t") - if esc := appendEscapedText(buf, "hallo\tescape"); string(esc) != "123\thallo\\tescape" { - t.Fatal(string(esc)) - } - buf = []byte("123\t") - if esc := appendEscapedText(buf, "hallo\\tescape\n"); string(esc) != "123\thallo\\\\tescape\\n" { - t.Fatal(string(esc)) - } - buf = []byte("123\t") - if esc := appendEscapedText(buf, "\n\r\t\f"); string(esc) != "123\t\\n\\r\\t\f" { - t.Fatal(string(esc)) - } -} - -func BenchmarkAppendEscapedText(b *testing.B) { - longString := "" - for i := 0; i < 100; i++ { - longString += "123456789\n" - } - for i := 0; i < b.N; i++ { - appendEscapedText(nil, longString) - } -} - -func BenchmarkAppendEscapedTextNoEscape(b *testing.B) { - longString := "" - for i := 0; i < 100; i++ { - longString += "1234567890" - } - for i := 0; i < b.N; i++ { - appendEscapedText(nil, longString) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/error.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/error.go deleted file mode 100644 index 5cfe9c6e9..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/error.go +++ /dev/null @@ -1,518 +0,0 @@ -package pq - -import ( - "database/sql/driver" - "fmt" - "io" - "net" - "runtime" -) - -// Error severities -const ( - Efatal = "FATAL" - Epanic = "PANIC" - Ewarning = "WARNING" - Enotice = "NOTICE" - Edebug = "DEBUG" - Einfo = "INFO" - Elog = "LOG" -) - -// Error represents an error communicating with the server. -// -// See http://www.postgresql.org/docs/current/static/protocol-error-fields.html for details of the fields -type Error struct { - Severity string - Code ErrorCode - Message string - Detail string - Hint string - Position string - InternalPosition string - InternalQuery string - Where string - Schema string - Table string - Column string - DataTypeName string - Constraint string - File string - Line string - Routine string -} - -// ErrorCode is a five-character error code. -type ErrorCode string - -// Name returns a more human friendly rendering of the error code, namely the -// "condition name". -// -// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for -// details. -func (ec ErrorCode) Name() string { - return errorCodeNames[ec] -} - -// ErrorClass is only the class part of an error code. -type ErrorClass string - -// Name returns the condition name of an error class. It is equivalent to the -// condition name of the "standard" error code (i.e. the one having the last -// three characters "000"). -func (ec ErrorClass) Name() string { - return errorCodeNames[ErrorCode(ec+"000")] -} - -// Class returns the error class, e.g. "28". -// -// See http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html for -// details. -func (ec ErrorCode) Class() ErrorClass { - return ErrorClass(ec[0:2]) -} - -// errorCodeNames is a mapping between the five-character error codes and the -// human readable "condition names". It is derived from the list at -// http://www.postgresql.org/docs/9.3/static/errcodes-appendix.html -var errorCodeNames = map[ErrorCode]string{ - // Class 00 - Successful Completion - "00000": "successful_completion", - // Class 01 - Warning - "01000": "warning", - "0100C": "dynamic_result_sets_returned", - "01008": "implicit_zero_bit_padding", - "01003": "null_value_eliminated_in_set_function", - "01007": "privilege_not_granted", - "01006": "privilege_not_revoked", - "01004": "string_data_right_truncation", - "01P01": "deprecated_feature", - // Class 02 - No Data (this is also a warning class per the SQL standard) - "02000": "no_data", - "02001": "no_additional_dynamic_result_sets_returned", - // Class 03 - SQL Statement Not Yet Complete - "03000": "sql_statement_not_yet_complete", - // Class 08 - Connection Exception - "08000": "connection_exception", - "08003": "connection_does_not_exist", - "08006": "connection_failure", - "08001": "sqlclient_unable_to_establish_sqlconnection", - "08004": "sqlserver_rejected_establishment_of_sqlconnection", - "08007": "transaction_resolution_unknown", - "08P01": "protocol_violation", - // Class 09 - Triggered Action Exception - "09000": "triggered_action_exception", - // Class 0A - Feature Not Supported - "0A000": "feature_not_supported", - // Class 0B - Invalid Transaction Initiation - "0B000": "invalid_transaction_initiation", - // Class 0F - Locator Exception - "0F000": "locator_exception", - "0F001": "invalid_locator_specification", - // Class 0L - Invalid Grantor - "0L000": "invalid_grantor", - "0LP01": "invalid_grant_operation", - // Class 0P - Invalid Role Specification - "0P000": "invalid_role_specification", - // Class 0Z - Diagnostics Exception - "0Z000": "diagnostics_exception", - "0Z002": "stacked_diagnostics_accessed_without_active_handler", - // Class 20 - Case Not Found - "20000": "case_not_found", - // Class 21 - Cardinality Violation - "21000": "cardinality_violation", - // Class 22 - Data Exception - "22000": "data_exception", - "2202E": "array_subscript_error", - "22021": "character_not_in_repertoire", - "22008": "datetime_field_overflow", - "22012": "division_by_zero", - "22005": "error_in_assignment", - "2200B": "escape_character_conflict", - "22022": "indicator_overflow", - "22015": "interval_field_overflow", - "2201E": "invalid_argument_for_logarithm", - "22014": "invalid_argument_for_ntile_function", - "22016": "invalid_argument_for_nth_value_function", - "2201F": "invalid_argument_for_power_function", - "2201G": "invalid_argument_for_width_bucket_function", - "22018": "invalid_character_value_for_cast", - "22007": "invalid_datetime_format", - "22019": "invalid_escape_character", - "2200D": "invalid_escape_octet", - "22025": "invalid_escape_sequence", - "22P06": "nonstandard_use_of_escape_character", - "22010": "invalid_indicator_parameter_value", - "22023": "invalid_parameter_value", - "2201B": "invalid_regular_expression", - "2201W": "invalid_row_count_in_limit_clause", - "2201X": "invalid_row_count_in_result_offset_clause", - "22009": "invalid_time_zone_displacement_value", - "2200C": "invalid_use_of_escape_character", - "2200G": "most_specific_type_mismatch", - "22004": "null_value_not_allowed", - "22002": "null_value_no_indicator_parameter", - "22003": "numeric_value_out_of_range", - "2200H": "sequence_generator_limit_exceeded", - "22026": "string_data_length_mismatch", - "22001": "string_data_right_truncation", - "22011": "substring_error", - "22027": "trim_error", - "22024": "unterminated_c_string", - "2200F": "zero_length_character_string", - "22P01": "floating_point_exception", - "22P02": "invalid_text_representation", - "22P03": "invalid_binary_representation", - "22P04": "bad_copy_file_format", - "22P05": "untranslatable_character", - "2200L": "not_an_xml_document", - "2200M": "invalid_xml_document", - "2200N": "invalid_xml_content", - "2200S": "invalid_xml_comment", - "2200T": "invalid_xml_processing_instruction", - // Class 23 - Integrity Constraint Violation - "23000": "integrity_constraint_violation", - "23001": "restrict_violation", - "23502": "not_null_violation", - "23503": "foreign_key_violation", - "23505": "unique_violation", - "23514": "check_violation", - "23P01": "exclusion_violation", - // Class 24 - Invalid Cursor State - "24000": "invalid_cursor_state", - // Class 25 - Invalid Transaction State - "25000": "invalid_transaction_state", - "25001": "active_sql_transaction", - "25002": "branch_transaction_already_active", - "25008": "held_cursor_requires_same_isolation_level", - "25003": "inappropriate_access_mode_for_branch_transaction", - "25004": "inappropriate_isolation_level_for_branch_transaction", - "25005": "no_active_sql_transaction_for_branch_transaction", - "25006": "read_only_sql_transaction", - "25007": "schema_and_data_statement_mixing_not_supported", - "25P01": "no_active_sql_transaction", - "25P02": "in_failed_sql_transaction", - // Class 26 - Invalid SQL Statement Name - "26000": "invalid_sql_statement_name", - // Class 27 - Triggered Data Change Violation - "27000": "triggered_data_change_violation", - // Class 28 - Invalid Authorization Specification - "28000": "invalid_authorization_specification", - "28P01": "invalid_password", - // Class 2B - Dependent Privilege Descriptors Still Exist - "2B000": "dependent_privilege_descriptors_still_exist", - "2BP01": "dependent_objects_still_exist", - // Class 2D - Invalid Transaction Termination - "2D000": "invalid_transaction_termination", - // Class 2F - SQL Routine Exception - "2F000": "sql_routine_exception", - "2F005": "function_executed_no_return_statement", - "2F002": "modifying_sql_data_not_permitted", - "2F003": "prohibited_sql_statement_attempted", - "2F004": "reading_sql_data_not_permitted", - // Class 34 - Invalid Cursor Name - "34000": "invalid_cursor_name", - // Class 38 - External Routine Exception - "38000": "external_routine_exception", - "38001": "containing_sql_not_permitted", - "38002": "modifying_sql_data_not_permitted", - "38003": "prohibited_sql_statement_attempted", - "38004": "reading_sql_data_not_permitted", - // Class 39 - External Routine Invocation Exception - "39000": "external_routine_invocation_exception", - "39001": "invalid_sqlstate_returned", - "39004": "null_value_not_allowed", - "39P01": "trigger_protocol_violated", - "39P02": "srf_protocol_violated", - // Class 3B - Savepoint Exception - "3B000": "savepoint_exception", - "3B001": "invalid_savepoint_specification", - // Class 3D - Invalid Catalog Name - "3D000": "invalid_catalog_name", - // Class 3F - Invalid Schema Name - "3F000": "invalid_schema_name", - // Class 40 - Transaction Rollback - "40000": "transaction_rollback", - "40002": "transaction_integrity_constraint_violation", - "40001": "serialization_failure", - "40003": "statement_completion_unknown", - "40P01": "deadlock_detected", - // Class 42 - Syntax Error or Access Rule Violation - "42000": "syntax_error_or_access_rule_violation", - "42601": "syntax_error", - "42501": "insufficient_privilege", - "42846": "cannot_coerce", - "42803": "grouping_error", - "42P20": "windowing_error", - "42P19": "invalid_recursion", - "42830": "invalid_foreign_key", - "42602": "invalid_name", - "42622": "name_too_long", - "42939": "reserved_name", - "42804": "datatype_mismatch", - "42P18": "indeterminate_datatype", - "42P21": "collation_mismatch", - "42P22": "indeterminate_collation", - "42809": "wrong_object_type", - "42703": "undefined_column", - "42883": "undefined_function", - "42P01": "undefined_table", - "42P02": "undefined_parameter", - "42704": "undefined_object", - "42701": "duplicate_column", - "42P03": "duplicate_cursor", - "42P04": "duplicate_database", - "42723": "duplicate_function", - "42P05": "duplicate_prepared_statement", - "42P06": "duplicate_schema", - "42P07": "duplicate_table", - "42712": "duplicate_alias", - "42710": "duplicate_object", - "42702": "ambiguous_column", - "42725": "ambiguous_function", - "42P08": "ambiguous_parameter", - "42P09": "ambiguous_alias", - "42P10": "invalid_column_reference", - "42611": "invalid_column_definition", - "42P11": "invalid_cursor_definition", - "42P12": "invalid_database_definition", - "42P13": "invalid_function_definition", - "42P14": "invalid_prepared_statement_definition", - "42P15": "invalid_schema_definition", - "42P16": "invalid_table_definition", - "42P17": "invalid_object_definition", - // Class 44 - WITH CHECK OPTION Violation - "44000": "with_check_option_violation", - // Class 53 - Insufficient Resources - "53000": "insufficient_resources", - "53100": "disk_full", - "53200": "out_of_memory", - "53300": "too_many_connections", - "53400": "configuration_limit_exceeded", - // Class 54 - Program Limit Exceeded - "54000": "program_limit_exceeded", - "54001": "statement_too_complex", - "54011": "too_many_columns", - "54023": "too_many_arguments", - // Class 55 - Object Not In Prerequisite State - "55000": "object_not_in_prerequisite_state", - "55006": "object_in_use", - "55P02": "cant_change_runtime_param", - "55P03": "lock_not_available", - // Class 57 - Operator Intervention - "57000": "operator_intervention", - "57014": "query_canceled", - "57P01": "admin_shutdown", - "57P02": "crash_shutdown", - "57P03": "cannot_connect_now", - "57P04": "database_dropped", - // Class 58 - System Error (errors external to PostgreSQL itself) - "58000": "system_error", - "58030": "io_error", - "58P01": "undefined_file", - "58P02": "duplicate_file", - // Class F0 - Configuration File Error - "F0000": "config_file_error", - "F0001": "lock_file_exists", - // Class HV - Foreign Data Wrapper Error (SQL/MED) - "HV000": "fdw_error", - "HV005": "fdw_column_name_not_found", - "HV002": "fdw_dynamic_parameter_value_needed", - "HV010": "fdw_function_sequence_error", - "HV021": "fdw_inconsistent_descriptor_information", - "HV024": "fdw_invalid_attribute_value", - "HV007": "fdw_invalid_column_name", - "HV008": "fdw_invalid_column_number", - "HV004": "fdw_invalid_data_type", - "HV006": "fdw_invalid_data_type_descriptors", - "HV091": "fdw_invalid_descriptor_field_identifier", - "HV00B": "fdw_invalid_handle", - "HV00C": "fdw_invalid_option_index", - "HV00D": "fdw_invalid_option_name", - "HV090": "fdw_invalid_string_length_or_buffer_length", - "HV00A": "fdw_invalid_string_format", - "HV009": "fdw_invalid_use_of_null_pointer", - "HV014": "fdw_too_many_handles", - "HV001": "fdw_out_of_memory", - "HV00P": "fdw_no_schemas", - "HV00J": "fdw_option_name_not_found", - "HV00K": "fdw_reply_handle", - "HV00Q": "fdw_schema_not_found", - "HV00R": "fdw_table_not_found", - "HV00L": "fdw_unable_to_create_execution", - "HV00M": "fdw_unable_to_create_reply", - "HV00N": "fdw_unable_to_establish_connection", - // Class P0 - PL/pgSQL Error - "P0000": "plpgsql_error", - "P0001": "raise_exception", - "P0002": "no_data_found", - "P0003": "too_many_rows", - // Class XX - Internal Error - "XX000": "internal_error", - "XX001": "data_corrupted", - "XX002": "index_corrupted", -} - -func parseError(r *readBuf) *Error { - err := new(Error) - for t := r.byte(); t != 0; t = r.byte() { - msg := r.string() - switch t { - case 'S': - err.Severity = msg - case 'C': - err.Code = ErrorCode(msg) - case 'M': - err.Message = msg - case 'D': - err.Detail = msg - case 'H': - err.Hint = msg - case 'P': - err.Position = msg - case 'p': - err.InternalPosition = msg - case 'q': - err.InternalQuery = msg - case 'W': - err.Where = msg - case 's': - err.Schema = msg - case 't': - err.Table = msg - case 'c': - err.Column = msg - case 'd': - err.DataTypeName = msg - case 'n': - err.Constraint = msg - case 'F': - err.File = msg - case 'L': - err.Line = msg - case 'R': - err.Routine = msg - } - } - return err -} - -// Fatal returns true if the Error Severity is fatal. -func (err *Error) Fatal() bool { - return err.Severity == Efatal -} - -// Get implements the legacy PGError interface. New code should use the fields -// of the Error struct directly. -func (err *Error) Get(k byte) (v string) { - switch k { - case 'S': - return err.Severity - case 'C': - return string(err.Code) - case 'M': - return err.Message - case 'D': - return err.Detail - case 'H': - return err.Hint - case 'P': - return err.Position - case 'p': - return err.InternalPosition - case 'q': - return err.InternalQuery - case 'W': - return err.Where - case 's': - return err.Schema - case 't': - return err.Table - case 'c': - return err.Column - case 'd': - return err.DataTypeName - case 'n': - return err.Constraint - case 'F': - return err.File - case 'L': - return err.Line - case 'R': - return err.Routine - } - return "" -} - -func (err Error) Error() string { - return "pq: " + err.Message -} - -// PGError is an interface used by previous versions of pq. It is provided -// only to support legacy code. New code should use the Error type. -type PGError interface { - Error() string - Fatal() bool - Get(k byte) (v string) -} - -func errorf(s string, args ...interface{}) { - panic(fmt.Errorf("pq: %s", fmt.Sprintf(s, args...))) -} - -// TODO(ainar-g) Rename to errorf after removing panics. -func fmterrorf(s string, args ...interface{}) error { - return fmt.Errorf("pq: %s", fmt.Sprintf(s, args...)) -} - -func errRecoverNoErrBadConn(err *error) { - e := recover() - if e == nil { - // Do nothing - return - } - var ok bool - *err, ok = e.(error) - if !ok { - *err = fmt.Errorf("pq: unexpected error: %#v", e) - } -} - -func (cn *conn) errRecover(err *error) { - e := recover() - switch v := e.(type) { - case nil: - // Do nothing - case runtime.Error: - cn.err.set(driver.ErrBadConn) - panic(v) - case *Error: - if v.Fatal() { - *err = driver.ErrBadConn - } else { - *err = v - } - case *net.OpError: - cn.err.set(driver.ErrBadConn) - *err = v - case *safeRetryError: - cn.err.set(driver.ErrBadConn) - *err = driver.ErrBadConn - case error: - if v == io.EOF || v.Error() == "remote error: handshake failure" { - *err = driver.ErrBadConn - } else { - *err = v - } - - default: - cn.err.set(driver.ErrBadConn) - panic(fmt.Sprintf("unknown error: %#v", e)) - } - - // Any time we return ErrBadConn, we need to remember it since *Tx doesn't - // mark the connection bad in database/sql. - if *err == driver.ErrBadConn { - cn.err.set(driver.ErrBadConn) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/example/listen/doc.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/example/listen/doc.go deleted file mode 100644 index 91e2ddbad..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/example/listen/doc.go +++ /dev/null @@ -1,98 +0,0 @@ -/* - -Package listen is a self-contained Go program which uses the LISTEN / NOTIFY -mechanism to avoid polling the database while waiting for more work to arrive. - - // - // You can see the program in action by defining a function similar to - // the following: - // - // CREATE OR REPLACE FUNCTION public.get_work() - // RETURNS bigint - // LANGUAGE sql - // AS $$ - // SELECT CASE WHEN random() >= 0.2 THEN int8 '1' END - // $$ - // ; - - package main - - import ( - "database/sql" - "fmt" - "time" - - "github.com/lib/pq" - ) - - func doWork(db *sql.DB, work int64) { - // work here - } - - func getWork(db *sql.DB) { - for { - // get work from the database here - var work sql.NullInt64 - err := db.QueryRow("SELECT get_work()").Scan(&work) - if err != nil { - fmt.Println("call to get_work() failed: ", err) - time.Sleep(10 * time.Second) - continue - } - if !work.Valid { - // no more work to do - fmt.Println("ran out of work") - return - } - - fmt.Println("starting work on ", work.Int64) - go doWork(db, work.Int64) - } - } - - func waitForNotification(l *pq.Listener) { - select { - case <-l.Notify: - fmt.Println("received notification, new work available") - case <-time.After(90 * time.Second): - go l.Ping() - // Check if there's more work available, just in case it takes - // a while for the Listener to notice connection loss and - // reconnect. - fmt.Println("received no work for 90 seconds, checking for new work") - } - } - - func main() { - var conninfo string = "" - - db, err := sql.Open("postgres", conninfo) - if err != nil { - panic(err) - } - - reportProblem := func(ev pq.ListenerEventType, err error) { - if err != nil { - fmt.Println(err.Error()) - } - } - - minReconn := 10 * time.Second - maxReconn := time.Minute - listener := pq.NewListener(conninfo, minReconn, maxReconn, reportProblem) - err = listener.Listen("getwork") - if err != nil { - panic(err) - } - - fmt.Println("entering main loop") - for { - // process all available work before waiting for notifications - getWork(db) - waitForNotification(listener) - } - } - - -*/ -package listen diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/go.mod b/src/test/regress/go_driver_test/src/github.com/lib/pq/go.mod deleted file mode 100644 index b5a5639ab..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/go.mod +++ /dev/null @@ -1,3 +0,0 @@ -module github.com/lib/pq - -go 1.13 diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/go18_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/go18_test.go deleted file mode 100644 index 27501e74a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/go18_test.go +++ /dev/null @@ -1,333 +0,0 @@ -package pq - -import ( - "context" - "database/sql" - "database/sql/driver" - "runtime" - "strings" - "testing" - "time" -) - -func TestMultipleSimpleQuery(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - rows, err := db.Query("select 1; set time zone default; select 2; select 3") - if err != nil { - t.Fatal(err) - } - defer rows.Close() - - var i int - for rows.Next() { - if err := rows.Scan(&i); err != nil { - t.Fatal(err) - } - if i != 1 { - t.Fatalf("expected 1, got %d", i) - } - } - if !rows.NextResultSet() { - t.Fatal("expected more result sets", rows.Err()) - } - for rows.Next() { - if err := rows.Scan(&i); err != nil { - t.Fatal(err) - } - if i != 2 { - t.Fatalf("expected 2, got %d", i) - } - } - - // Make sure that if we ignore a result we can still query. - - rows, err = db.Query("select 4; select 5") - if err != nil { - t.Fatal(err) - } - defer rows.Close() - - for rows.Next() { - if err := rows.Scan(&i); err != nil { - t.Fatal(err) - } - if i != 4 { - t.Fatalf("expected 4, got %d", i) - } - } - if !rows.NextResultSet() { - t.Fatal("expected more result sets", rows.Err()) - } - for rows.Next() { - if err := rows.Scan(&i); err != nil { - t.Fatal(err) - } - if i != 5 { - t.Fatalf("expected 5, got %d", i) - } - } - if rows.NextResultSet() { - t.Fatal("unexpected result set") - } -} - -const contextRaceIterations = 100 - -func TestContextCancelExec(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - ctx, cancel := context.WithCancel(context.Background()) - - // Delay execution for just a bit until db.ExecContext has begun. - defer time.AfterFunc(time.Millisecond*10, cancel).Stop() - - // Not canceled until after the exec has started. - if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil { - t.Fatal("expected error") - } else if err.Error() != "pq: canceling statement due to user request" { - t.Fatalf("unexpected error: %s", err) - } - - // Context is already canceled, so error should come before execution. - if _, err := db.ExecContext(ctx, "select pg_sleep(1)"); err == nil { - t.Fatal("expected error") - } else if err.Error() != "context canceled" { - t.Fatalf("unexpected error: %s", err) - } - - for i := 0; i < contextRaceIterations; i++ { - func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - if _, err := db.ExecContext(ctx, "select 1"); err != nil { - t.Fatal(err) - } - }() - - if _, err := db.Exec("select 1"); err != nil { - t.Fatal(err) - } - } -} - -func TestContextCancelQuery(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - ctx, cancel := context.WithCancel(context.Background()) - - // Delay execution for just a bit until db.QueryContext has begun. - defer time.AfterFunc(time.Millisecond*10, cancel).Stop() - - // Not canceled until after the exec has started. - if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil { - t.Fatal("expected error") - } else if err.Error() != "pq: canceling statement due to user request" { - t.Fatalf("unexpected error: %s", err) - } - - // Context is already canceled, so error should come before execution. - if _, err := db.QueryContext(ctx, "select pg_sleep(1)"); err == nil { - t.Fatal("expected error") - } else if err.Error() != "context canceled" { - t.Fatalf("unexpected error: %s", err) - } - - for i := 0; i < contextRaceIterations; i++ { - func() { - ctx, cancel := context.WithCancel(context.Background()) - rows, err := db.QueryContext(ctx, "select 1") - cancel() - if err != nil { - t.Fatal(err) - } else if err := rows.Close(); err != nil && err != driver.ErrBadConn && err != context.Canceled { - t.Fatal(err) - } - }() - - if rows, err := db.Query("select 1"); err != nil { - t.Fatal(err) - } else if err := rows.Close(); err != nil { - t.Fatal(err) - } - } -} - -// TestIssue617 tests that a failed query in QueryContext doesn't lead to a -// goroutine leak. -func TestIssue617(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - const N = 10 - - numGoroutineStart := runtime.NumGoroutine() - for i := 0; i < N; i++ { - func() { - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - _, err := db.QueryContext(ctx, `SELECT * FROM DOESNOTEXIST`) - pqErr, _ := err.(*Error) - // Expecting "pq: relation \"doesnotexist\" does not exist" error. - if err == nil || pqErr == nil || pqErr.Code != "42P01" { - t.Fatalf("expected undefined table error, got %v", err) - } - }() - } - - // Give time for goroutines to terminate - delayTime := time.Millisecond * 50 - waitTime := time.Second - iterations := int(waitTime / delayTime) - - var numGoroutineFinish int - for i := 0; i < iterations; i++ { - time.Sleep(delayTime) - - numGoroutineFinish = runtime.NumGoroutine() - - // We use N/2 and not N because the GC and other actors may increase or - // decrease the number of goroutines. - if numGoroutineFinish-numGoroutineStart < N/2 { - return - } - } - - t.Errorf("goroutine leak detected, was %d, now %d", numGoroutineStart, numGoroutineFinish) -} - -func TestContextCancelBegin(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - ctx, cancel := context.WithCancel(context.Background()) - tx, err := db.BeginTx(ctx, nil) - if err != nil { - t.Fatal(err) - } - - // Delay execution for just a bit until tx.Exec has begun. - defer time.AfterFunc(time.Millisecond*10, cancel).Stop() - - // Not canceled until after the exec has started. - if _, err := tx.Exec("select pg_sleep(1)"); err == nil { - t.Fatal("expected error") - } else if err.Error() != "pq: canceling statement due to user request" { - t.Fatalf("unexpected error: %s", err) - } - - // Transaction is canceled, so expect an error. - if _, err := tx.Query("select pg_sleep(1)"); err == nil { - t.Fatal("expected error") - } else if err != sql.ErrTxDone { - t.Fatalf("unexpected error: %s", err) - } - - // Context is canceled, so cannot begin a transaction. - if _, err := db.BeginTx(ctx, nil); err == nil { - t.Fatal("expected error") - } else if err.Error() != "context canceled" { - t.Fatalf("unexpected error: %s", err) - } - - for i := 0; i < contextRaceIterations; i++ { - func() { - ctx, cancel := context.WithCancel(context.Background()) - tx, err := db.BeginTx(ctx, nil) - cancel() - if err != nil { - t.Fatal(err) - } else if err := tx.Rollback(); err != nil && - err.Error() != "pq: canceling statement due to user request" && - err != sql.ErrTxDone && err != driver.ErrBadConn && err != context.Canceled { - t.Fatal(err) - } - }() - - if tx, err := db.Begin(); err != nil { - t.Fatal(err) - } else if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - } -} - -func TestTxOptions(t *testing.T) { - db := openTestConn(t) - defer db.Close() - ctx := context.Background() - - tests := []struct { - level sql.IsolationLevel - isolation string - }{ - { - level: sql.LevelDefault, - isolation: "", - }, - { - level: sql.LevelReadUncommitted, - isolation: "read uncommitted", - }, - { - level: sql.LevelReadCommitted, - isolation: "read committed", - }, - { - level: sql.LevelRepeatableRead, - isolation: "repeatable read", - }, - { - level: sql.LevelSerializable, - isolation: "serializable", - }, - } - - for _, test := range tests { - for _, ro := range []bool{true, false} { - tx, err := db.BeginTx(ctx, &sql.TxOptions{ - Isolation: test.level, - ReadOnly: ro, - }) - if err != nil { - t.Fatal(err) - } - - var isolation string - err = tx.QueryRow("select current_setting('transaction_isolation')").Scan(&isolation) - if err != nil { - t.Fatal(err) - } - - if test.isolation != "" && isolation != test.isolation { - t.Errorf("wrong isolation level: %s != %s", isolation, test.isolation) - } - - var isRO string - err = tx.QueryRow("select current_setting('transaction_read_only')").Scan(&isRO) - if err != nil { - t.Fatal(err) - } - - if ro != (isRO == "on") { - t.Errorf("read/[write,only] not set: %t != %s for level %s", - ro, isRO, test.isolation) - } - - tx.Rollback() - } - } - - _, err := db.BeginTx(ctx, &sql.TxOptions{ - Isolation: sql.LevelLinearizable, - }) - if err == nil { - t.Fatal("expected LevelLinearizable to fail") - } - if !strings.Contains(err.Error(), "isolation level not supported") { - t.Errorf("Expected error to mention isolation level, got %q", err) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/go19_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/go19_test.go deleted file mode 100644 index f810e4890..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/go19_test.go +++ /dev/null @@ -1,99 +0,0 @@ -//go:build go1.9 -// +build go1.9 - -package pq - -import ( - "context" - "database/sql" - "database/sql/driver" - "reflect" - "testing" -) - -func TestPing(t *testing.T) { - ctx, cancel := context.WithCancel(context.Background()) - db := openTestConn(t) - defer db.Close() - - if _, ok := reflect.TypeOf(db).MethodByName("Conn"); !ok { - t.Skipf("Conn method undefined on type %T, skipping test (requires at least go1.9)", db) - } - - if err := db.PingContext(ctx); err != nil { - t.Fatal("expected Ping to succeed") - } - defer cancel() - - // grab a connection - conn, err := db.Conn(ctx) - if err != nil { - t.Fatal(err) - } - - // start a transaction and read backend pid of our connection - tx, err := conn.BeginTx(ctx, &sql.TxOptions{ - Isolation: sql.LevelDefault, - ReadOnly: true, - }) - if err != nil { - t.Fatal(err) - } - - rows, err := tx.Query("SELECT pg_backend_pid()") - if err != nil { - t.Fatal(err) - } - defer rows.Close() - - // read the pid from result - var pid int - for rows.Next() { - if err := rows.Scan(&pid); err != nil { - t.Fatal(err) - } - } - if rows.Err() != nil { - t.Fatal(err) - } - // Fail the transaction and make sure we can still ping. - if _, err := tx.Query("INVALID SQL"); err == nil { - t.Fatal("expected error") - } - if err := conn.PingContext(ctx); err != nil { - t.Fatal(err) - } - if err := tx.Rollback(); err != nil { - t.Fatal(err) - } - - // kill the process which handles our connection and test if the ping fails - if _, err := db.Exec("SELECT pg_terminate_backend($1)", pid); err != nil { - t.Fatal(err) - } - if err := conn.PingContext(ctx); err != driver.ErrBadConn { - t.Fatalf("expected error %s, instead got %s", driver.ErrBadConn, err) - } -} - -func TestCommitInFailedTransactionWithCancelContext(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - ctx, cancel := context.WithCancel(context.Background()) - defer cancel() - - txn, err := db.BeginTx(ctx, nil) - if err != nil { - t.Fatal(err) - } - rows, err := txn.Query("SELECT error") - if err == nil { - rows.Close() - t.Fatal("expected failure") - } - err = txn.Commit() - if err != ErrInFailedTransaction { - t.Fatalf("expected ErrInFailedTransaction; got %#v", err) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/hstore/hstore.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/hstore/hstore.go deleted file mode 100644 index f1470db14..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/hstore/hstore.go +++ /dev/null @@ -1,118 +0,0 @@ -package hstore - -import ( - "database/sql" - "database/sql/driver" - "strings" -) - -// Hstore is a wrapper for transferring Hstore values back and forth easily. -type Hstore struct { - Map map[string]sql.NullString -} - -// escapes and quotes hstore keys/values -// s should be a sql.NullString or string -func hQuote(s interface{}) string { - var str string - switch v := s.(type) { - case sql.NullString: - if !v.Valid { - return "NULL" - } - str = v.String - case string: - str = v - default: - panic("not a string or sql.NullString") - } - - str = strings.Replace(str, "\\", "\\\\", -1) - return `"` + strings.Replace(str, "\"", "\\\"", -1) + `"` -} - -// Scan implements the Scanner interface. -// -// Note h.Map is reallocated before the scan to clear existing values. If the -// hstore column's database value is NULL, then h.Map is set to nil instead. -func (h *Hstore) Scan(value interface{}) error { - if value == nil { - h.Map = nil - return nil - } - h.Map = make(map[string]sql.NullString) - var b byte - pair := [][]byte{{}, {}} - pi := 0 - inQuote := false - didQuote := false - sawSlash := false - bindex := 0 - for bindex, b = range value.([]byte) { - if sawSlash { - pair[pi] = append(pair[pi], b) - sawSlash = false - continue - } - - switch b { - case '\\': - sawSlash = true - continue - case '"': - inQuote = !inQuote - if !didQuote { - didQuote = true - } - continue - default: - if !inQuote { - switch b { - case ' ', '\t', '\n', '\r': - continue - case '=': - continue - case '>': - pi = 1 - didQuote = false - continue - case ',': - s := string(pair[1]) - if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { - h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false} - } else { - h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true} - } - pair[0] = []byte{} - pair[1] = []byte{} - pi = 0 - continue - } - } - } - pair[pi] = append(pair[pi], b) - } - if bindex > 0 { - s := string(pair[1]) - if !didQuote && len(s) == 4 && strings.ToLower(s) == "null" { - h.Map[string(pair[0])] = sql.NullString{String: "", Valid: false} - } else { - h.Map[string(pair[0])] = sql.NullString{String: string(pair[1]), Valid: true} - } - } - return nil -} - -// Value implements the driver Valuer interface. Note if h.Map is nil, the -// database column value will be set to NULL. -func (h Hstore) Value() (driver.Value, error) { - if h.Map == nil { - return nil, nil - } - parts := []string{} - for key, val := range h.Map { - thispart := hQuote(key) + "=>" + hQuote(val) - parts = append(parts, thispart) - } - return []byte(strings.Join(parts, ",")), nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/hstore/hstore_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/hstore/hstore_test.go deleted file mode 100644 index 0d361ae94..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/hstore/hstore_test.go +++ /dev/null @@ -1,148 +0,0 @@ -package hstore - -import ( - "database/sql" - "os" - "testing" - - _ "github.com/lib/pq" -) - -type Fatalistic interface { - Fatal(args ...interface{}) -} - -func openTestConn(t Fatalistic) *sql.DB { - datname := os.Getenv("PGDATABASE") - sslmode := os.Getenv("PGSSLMODE") - - if datname == "" { - os.Setenv("PGDATABASE", "pqgotest") - } - - if sslmode == "" { - os.Setenv("PGSSLMODE", "disable") - } - - conn, err := sql.Open("postgres", "") - if err != nil { - t.Fatal(err) - } - - return conn -} - -func TestHstore(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - // quietly create hstore if it doesn't exist - _, err := db.Exec("CREATE EXTENSION IF NOT EXISTS hstore") - if err != nil { - t.Skipf("Skipping hstore tests - hstore extension create failed: %s", err.Error()) - } - - hs := Hstore{} - - // test for null-valued hstores - err = db.QueryRow("SELECT NULL::hstore").Scan(&hs) - if err != nil { - t.Fatal(err) - } - if hs.Map != nil { - t.Fatalf("expected null map") - } - - err = db.QueryRow("SELECT $1::hstore", hs).Scan(&hs) - if err != nil { - t.Fatalf("re-query null map failed: %s", err.Error()) - } - if hs.Map != nil { - t.Fatalf("expected null map") - } - - // test for empty hstores - err = db.QueryRow("SELECT ''::hstore").Scan(&hs) - if err != nil { - t.Fatal(err) - } - if hs.Map == nil { - t.Fatalf("expected empty map, got null map") - } - if len(hs.Map) != 0 { - t.Fatalf("expected empty map, got len(map)=%d", len(hs.Map)) - } - - err = db.QueryRow("SELECT $1::hstore", hs).Scan(&hs) - if err != nil { - t.Fatalf("re-query empty map failed: %s", err.Error()) - } - if hs.Map == nil { - t.Fatalf("expected empty map, got null map") - } - if len(hs.Map) != 0 { - t.Fatalf("expected empty map, got len(map)=%d", len(hs.Map)) - } - - // a few example maps to test out - hsOnePair := Hstore{ - Map: map[string]sql.NullString{ - "key1": {String: "value1", Valid: true}, - }, - } - - hsThreePairs := Hstore{ - Map: map[string]sql.NullString{ - "key1": {String: "value1", Valid: true}, - "key2": {String: "value2", Valid: true}, - "key3": {String: "value3", Valid: true}, - }, - } - - hsSmorgasbord := Hstore{ - Map: map[string]sql.NullString{ - "nullstring": {String: "NULL", Valid: true}, - "actuallynull": {String: "", Valid: false}, - "NULL": {String: "NULL string key", Valid: true}, - "withbracket": {String: "value>42", Valid: true}, - "withequal": {String: "value=42", Valid: true}, - `"withquotes1"`: {String: `this "should" be fine`, Valid: true}, - `"withquotes"2"`: {String: `this "should\" also be fine`, Valid: true}, - "embedded1": {String: "value1=>x1", Valid: true}, - "embedded2": {String: `"value2"=>x2`, Valid: true}, - "withnewlines": {String: "\n\nvalue\t=>2", Valid: true}, - "<>": {String: `this, "should,\" also, => be fine`, Valid: true}, - }, - } - - // test encoding in query params, then decoding during Scan - testBidirectional := func(h Hstore) { - err = db.QueryRow("SELECT $1::hstore", h).Scan(&hs) - if err != nil { - t.Fatalf("re-query %d-pair map failed: %s", len(h.Map), err.Error()) - } - if hs.Map == nil { - t.Fatalf("expected %d-pair map, got null map", len(h.Map)) - } - if len(hs.Map) != len(h.Map) { - t.Fatalf("expected %d-pair map, got len(map)=%d", len(h.Map), len(hs.Map)) - } - - for key, val := range hs.Map { - otherval, found := h.Map[key] - if !found { - t.Fatalf(" key '%v' not found in %d-pair map", key, len(h.Map)) - } - if otherval.Valid != val.Valid { - t.Fatalf(" value %v <> %v in %d-pair map", otherval, val, len(h.Map)) - } - if otherval.String != val.String { - t.Fatalf(" value '%v' <> '%v' in %d-pair map", otherval.String, val.String, len(h.Map)) - } - } - } - - testBidirectional(hsOnePair) - testBidirectional(hsThreePairs) - testBidirectional(hsSmorgasbord) -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/issues_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/issues_test.go deleted file mode 100644 index 4d24c9ddd..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/issues_test.go +++ /dev/null @@ -1,79 +0,0 @@ -package pq - -import ( - "context" - "testing" - "time" -) - -func TestIssue494(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - query := `CREATE TEMP TABLE t (i INT PRIMARY KEY)` - if _, err := db.Exec(query); err != nil { - t.Fatal(err) - } - - txn, err := db.Begin() - if err != nil { - t.Fatal(err) - } - - if _, err := txn.Prepare(CopyIn("t", "i")); err != nil { - t.Fatal(err) - } - - if _, err := txn.Query("SELECT 1"); err == nil { - t.Fatal("expected error") - } -} - -func TestIssue1046(t *testing.T) { - ctxTimeout := time.Second * 2 - - db := openTestConn(t) - defer db.Close() - - ctx, cancel := context.WithTimeout(context.Background(), ctxTimeout) - defer cancel() - - stmt, err := db.PrepareContext(ctx, `SELECT pg_sleep(10) AS id`) - if err != nil { - t.Fatal(err) - } - - var d []uint8 - err = stmt.QueryRowContext(ctx).Scan(&d) - dl, _ := ctx.Deadline() - since := time.Since(dl) - if since > ctxTimeout { - t.Logf("FAIL %s: query returned after context deadline: %v\n", t.Name(), since) - t.Fail() - } - expectedErr := &Error{Message: "canceling statement due to user request"} - if err == nil || err.Error() != expectedErr.Error() { - t.Logf("ctx.Err(): [%T]%+v\n", ctx.Err(), ctx.Err()) - t.Logf("got err: [%T] %+v expected err: [%T] %+v", err, err, expectedErr, expectedErr) - t.Fail() - } -} - -func TestIssue1062(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - // Ensure that cancelling a QueryRowContext does not result in an ErrBadConn. - - for i := 0; i < 100; i++ { - ctx, cancel := context.WithCancel(context.Background()) - go cancel() - row := db.QueryRowContext(ctx, "select 1") - - var v int - err := row.Scan(&v) - if err != nil && err != context.Canceled && err.Error() != "pq: canceling statement due to user request" { - t.Fatalf("Scan resulted in unexpected error %v for canceled QueryRowContext at attempt %d", err, i+1) - } - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/krb.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/krb.go deleted file mode 100644 index 408ec01f9..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/krb.go +++ /dev/null @@ -1,27 +0,0 @@ -package pq - -// NewGSSFunc creates a GSS authentication provider, for use with -// RegisterGSSProvider. -type NewGSSFunc func() (GSS, error) - -var newGss NewGSSFunc - -// RegisterGSSProvider registers a GSS authentication provider. For example, if -// you need to use Kerberos to authenticate with your server, add this to your -// main package: -// -// import "github.com/lib/pq/auth/kerberos" -// -// func init() { -// pq.RegisterGSSProvider(func() (pq.GSS, error) { return kerberos.NewGSS() }) -// } -func RegisterGSSProvider(newGssArg NewGSSFunc) { - newGss = newGssArg -} - -// GSS provides GSSAPI authentication (e.g., Kerberos). -type GSS interface { - GetInitToken(host string, service string) ([]byte, error) - GetInitTokenFromSpn(spn string) ([]byte, error) - Continue(inToken []byte) (done bool, outToken []byte, err error) -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/notice.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/notice.go deleted file mode 100644 index 70ad122a7..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/notice.go +++ /dev/null @@ -1,72 +0,0 @@ -//go:build go1.10 -// +build go1.10 - -package pq - -import ( - "context" - "database/sql/driver" -) - -// NoticeHandler returns the notice handler on the given connection, if any. A -// runtime panic occurs if c is not a pq connection. This is rarely used -// directly, use ConnectorNoticeHandler and ConnectorWithNoticeHandler instead. -func NoticeHandler(c driver.Conn) func(*Error) { - return c.(*conn).noticeHandler -} - -// SetNoticeHandler sets the given notice handler on the given connection. A -// runtime panic occurs if c is not a pq connection. A nil handler may be used -// to unset it. This is rarely used directly, use ConnectorNoticeHandler and -// ConnectorWithNoticeHandler instead. -// -// Note: Notice handlers are executed synchronously by pq meaning commands -// won't continue to be processed until the handler returns. -func SetNoticeHandler(c driver.Conn, handler func(*Error)) { - c.(*conn).noticeHandler = handler -} - -// NoticeHandlerConnector wraps a regular connector and sets a notice handler -// on it. -type NoticeHandlerConnector struct { - driver.Connector - noticeHandler func(*Error) -} - -// Connect calls the underlying connector's connect method and then sets the -// notice handler. -func (n *NoticeHandlerConnector) Connect(ctx context.Context) (driver.Conn, error) { - c, err := n.Connector.Connect(ctx) - if err == nil { - SetNoticeHandler(c, n.noticeHandler) - } - return c, err -} - -// ConnectorNoticeHandler returns the currently set notice handler, if any. If -// the given connector is not a result of ConnectorWithNoticeHandler, nil is -// returned. -func ConnectorNoticeHandler(c driver.Connector) func(*Error) { - if c, ok := c.(*NoticeHandlerConnector); ok { - return c.noticeHandler - } - return nil -} - -// ConnectorWithNoticeHandler creates or sets the given handler for the given -// connector. If the given connector is a result of calling this function -// previously, it is simply set on the given connector and returned. Otherwise, -// this returns a new connector wrapping the given one and setting the notice -// handler. A nil notice handler may be used to unset it. -// -// The returned connector is intended to be used with database/sql.OpenDB. -// -// Note: Notice handlers are executed synchronously by pq meaning commands -// won't continue to be processed until the handler returns. -func ConnectorWithNoticeHandler(c driver.Connector, handler func(*Error)) *NoticeHandlerConnector { - if c, ok := c.(*NoticeHandlerConnector); ok { - c.noticeHandler = handler - return c - } - return &NoticeHandlerConnector{Connector: c, noticeHandler: handler} -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/notice_example_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/notice_example_test.go deleted file mode 100644 index 04bcb1d9d..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/notice_example_test.go +++ /dev/null @@ -1,34 +0,0 @@ -//go:build go1.10 -// +build go1.10 - -package pq_test - -import ( - "database/sql" - "fmt" - "log" - - "github.com/lib/pq" -) - -func ExampleConnectorWithNoticeHandler() { - name := "" - // Base connector to wrap - base, err := pq.NewConnector(name) - if err != nil { - log.Fatal(err) - } - // Wrap the connector to simply print out the message - connector := pq.ConnectorWithNoticeHandler(base, func(notice *pq.Error) { - fmt.Println("Notice sent: " + notice.Message) - }) - db := sql.OpenDB(connector) - defer db.Close() - // Raise a notice - sql := "DO language plpgsql $$ BEGIN RAISE NOTICE 'test notice'; END $$" - if _, err := db.Exec(sql); err != nil { - log.Fatal(err) - } - // Output: - // Notice sent: test notice -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/notice_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/notice_test.go deleted file mode 100644 index e9da9af3a..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/notice_test.go +++ /dev/null @@ -1,50 +0,0 @@ -//go:build go1.10 -// +build go1.10 - -package pq - -import ( - "database/sql" - "database/sql/driver" - "testing" -) - -func TestConnectorWithNoticeHandler_Simple(t *testing.T) { - b, err := NewConnector("") - if err != nil { - t.Fatal(err) - } - var notice *Error - // Make connector w/ handler to set the local var - c := ConnectorWithNoticeHandler(b, func(n *Error) { notice = n }) - raiseNotice(c, t, "Test notice #1") - if notice == nil || notice.Message != "Test notice #1" { - t.Fatalf("Expected notice w/ message, got %v", notice) - } - // Unset the handler on the same connector - prevC := c - if c = ConnectorWithNoticeHandler(c, nil); c != prevC { - t.Fatalf("Expected to not create new connector but did") - } - raiseNotice(c, t, "Test notice #2") - if notice == nil || notice.Message != "Test notice #1" { - t.Fatalf("Expected notice to not change, got %v", notice) - } - // Set it back on the same connector - if c = ConnectorWithNoticeHandler(c, func(n *Error) { notice = n }); c != prevC { - t.Fatal("Expected to not create new connector but did") - } - raiseNotice(c, t, "Test notice #3") - if notice == nil || notice.Message != "Test notice #3" { - t.Fatalf("Expected notice w/ message, got %v", notice) - } -} - -func raiseNotice(c driver.Connector, t *testing.T, escapedNotice string) { - db := sql.OpenDB(c) - defer db.Close() - sql := "DO language plpgsql $$ BEGIN RAISE NOTICE '" + escapedNotice + "'; END $$" - if _, err := db.Exec(sql); err != nil { - t.Fatal(err) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/notify.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/notify.go deleted file mode 100644 index 5c421fdb8..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/notify.go +++ /dev/null @@ -1,858 +0,0 @@ -package pq - -// Package pq is a pure Go Postgres driver for the database/sql package. -// This module contains support for Postgres LISTEN/NOTIFY. - -import ( - "context" - "database/sql/driver" - "errors" - "fmt" - "sync" - "sync/atomic" - "time" -) - -// Notification represents a single notification from the database. -type Notification struct { - // Process ID (PID) of the notifying postgres backend. - BePid int - // Name of the channel the notification was sent on. - Channel string - // Payload, or the empty string if unspecified. - Extra string -} - -func recvNotification(r *readBuf) *Notification { - bePid := r.int32() - channel := r.string() - extra := r.string() - - return &Notification{bePid, channel, extra} -} - -// SetNotificationHandler sets the given notification handler on the given -// connection. A runtime panic occurs if c is not a pq connection. A nil handler -// may be used to unset it. -// -// Note: Notification handlers are executed synchronously by pq meaning commands -// won't continue to be processed until the handler returns. -func SetNotificationHandler(c driver.Conn, handler func(*Notification)) { - c.(*conn).notificationHandler = handler -} - -// NotificationHandlerConnector wraps a regular connector and sets a notification handler -// on it. -type NotificationHandlerConnector struct { - driver.Connector - notificationHandler func(*Notification) -} - -// Connect calls the underlying connector's connect method and then sets the -// notification handler. -func (n *NotificationHandlerConnector) Connect(ctx context.Context) (driver.Conn, error) { - c, err := n.Connector.Connect(ctx) - if err == nil { - SetNotificationHandler(c, n.notificationHandler) - } - return c, err -} - -// ConnectorNotificationHandler returns the currently set notification handler, if any. If -// the given connector is not a result of ConnectorWithNotificationHandler, nil is -// returned. -func ConnectorNotificationHandler(c driver.Connector) func(*Notification) { - if c, ok := c.(*NotificationHandlerConnector); ok { - return c.notificationHandler - } - return nil -} - -// ConnectorWithNotificationHandler creates or sets the given handler for the given -// connector. If the given connector is a result of calling this function -// previously, it is simply set on the given connector and returned. Otherwise, -// this returns a new connector wrapping the given one and setting the notification -// handler. A nil notification handler may be used to unset it. -// -// The returned connector is intended to be used with database/sql.OpenDB. -// -// Note: Notification handlers are executed synchronously by pq meaning commands -// won't continue to be processed until the handler returns. -func ConnectorWithNotificationHandler(c driver.Connector, handler func(*Notification)) *NotificationHandlerConnector { - if c, ok := c.(*NotificationHandlerConnector); ok { - c.notificationHandler = handler - return c - } - return &NotificationHandlerConnector{Connector: c, notificationHandler: handler} -} - -const ( - connStateIdle int32 = iota - connStateExpectResponse - connStateExpectReadyForQuery -) - -type message struct { - typ byte - err error -} - -var errListenerConnClosed = errors.New("pq: ListenerConn has been closed") - -// ListenerConn is a low-level interface for waiting for notifications. You -// should use Listener instead. -type ListenerConn struct { - // guards cn and err - connectionLock sync.Mutex - cn *conn - err error - - connState int32 - - // the sending goroutine will be holding this lock - senderLock sync.Mutex - - notificationChan chan<- *Notification - - replyChan chan message -} - -// NewListenerConn creates a new ListenerConn. Use NewListener instead. -func NewListenerConn(name string, notificationChan chan<- *Notification) (*ListenerConn, error) { - return newDialListenerConn(defaultDialer{}, name, notificationChan) -} - -func newDialListenerConn(d Dialer, name string, c chan<- *Notification) (*ListenerConn, error) { - cn, err := DialOpen(d, name) - if err != nil { - return nil, err - } - - l := &ListenerConn{ - cn: cn.(*conn), - notificationChan: c, - connState: connStateIdle, - replyChan: make(chan message, 2), - } - - go l.listenerConnMain() - - return l, nil -} - -// We can only allow one goroutine at a time to be running a query on the -// connection for various reasons, so the goroutine sending on the connection -// must be holding senderLock. -// -// Returns an error if an unrecoverable error has occurred and the ListenerConn -// should be abandoned. -func (l *ListenerConn) acquireSenderLock() error { - // we must acquire senderLock first to avoid deadlocks; see ExecSimpleQuery - l.senderLock.Lock() - - l.connectionLock.Lock() - err := l.err - l.connectionLock.Unlock() - if err != nil { - l.senderLock.Unlock() - return err - } - return nil -} - -func (l *ListenerConn) releaseSenderLock() { - l.senderLock.Unlock() -} - -// setState advances the protocol state to newState. Returns false if moving -// to that state from the current state is not allowed. -func (l *ListenerConn) setState(newState int32) bool { - var expectedState int32 - - switch newState { - case connStateIdle: - expectedState = connStateExpectReadyForQuery - case connStateExpectResponse: - expectedState = connStateIdle - case connStateExpectReadyForQuery: - expectedState = connStateExpectResponse - default: - panic(fmt.Sprintf("unexpected listenerConnState %d", newState)) - } - - return atomic.CompareAndSwapInt32(&l.connState, expectedState, newState) -} - -// Main logic is here: receive messages from the postgres backend, forward -// notifications and query replies and keep the internal state in sync with the -// protocol state. Returns when the connection has been lost, is about to go -// away or should be discarded because we couldn't agree on the state with the -// server backend. -func (l *ListenerConn) listenerConnLoop() (err error) { - defer errRecoverNoErrBadConn(&err) - - r := &readBuf{} - for { - t, err := l.cn.recvMessage(r) - if err != nil { - return err - } - - switch t { - case 'A': - // recvNotification copies all the data so we don't need to worry - // about the scratch buffer being overwritten. - l.notificationChan <- recvNotification(r) - - case 'T', 'D': - // only used by tests; ignore - - case 'E': - // We might receive an ErrorResponse even when not in a query; it - // is expected that the server will close the connection after - // that, but we should make sure that the error we display is the - // one from the stray ErrorResponse, not io.ErrUnexpectedEOF. - if !l.setState(connStateExpectReadyForQuery) { - return parseError(r) - } - l.replyChan <- message{t, parseError(r)} - - case 'C', 'I': - if !l.setState(connStateExpectReadyForQuery) { - // protocol out of sync - return fmt.Errorf("unexpected CommandComplete") - } - // ExecSimpleQuery doesn't need to know about this message - - case 'Z': - if !l.setState(connStateIdle) { - // protocol out of sync - return fmt.Errorf("unexpected ReadyForQuery") - } - l.replyChan <- message{t, nil} - - case 'S': - // ignore - case 'N': - if n := l.cn.noticeHandler; n != nil { - n(parseError(r)) - } - default: - return fmt.Errorf("unexpected message %q from server in listenerConnLoop", t) - } - } -} - -// This is the main routine for the goroutine receiving on the database -// connection. Most of the main logic is in listenerConnLoop. -func (l *ListenerConn) listenerConnMain() { - err := l.listenerConnLoop() - - // listenerConnLoop terminated; we're done, but we still have to clean up. - // Make sure nobody tries to start any new queries by making sure the err - // pointer is set. It is important that we do not overwrite its value; a - // connection could be closed by either this goroutine or one sending on - // the connection -- whoever closes the connection is assumed to have the - // more meaningful error message (as the other one will probably get - // net.errClosed), so that goroutine sets the error we expose while the - // other error is discarded. If the connection is lost while two - // goroutines are operating on the socket, it probably doesn't matter which - // error we expose so we don't try to do anything more complex. - l.connectionLock.Lock() - if l.err == nil { - l.err = err - } - l.cn.Close() - l.connectionLock.Unlock() - - // There might be a query in-flight; make sure nobody's waiting for a - // response to it, since there's not going to be one. - close(l.replyChan) - - // let the listener know we're done - close(l.notificationChan) - - // this ListenerConn is done -} - -// Listen sends a LISTEN query to the server. See ExecSimpleQuery. -func (l *ListenerConn) Listen(channel string) (bool, error) { - return l.ExecSimpleQuery("LISTEN " + QuoteIdentifier(channel)) -} - -// Unlisten sends an UNLISTEN query to the server. See ExecSimpleQuery. -func (l *ListenerConn) Unlisten(channel string) (bool, error) { - return l.ExecSimpleQuery("UNLISTEN " + QuoteIdentifier(channel)) -} - -// UnlistenAll sends an `UNLISTEN *` query to the server. See ExecSimpleQuery. -func (l *ListenerConn) UnlistenAll() (bool, error) { - return l.ExecSimpleQuery("UNLISTEN *") -} - -// Ping the remote server to make sure it's alive. Non-nil error means the -// connection has failed and should be abandoned. -func (l *ListenerConn) Ping() error { - sent, err := l.ExecSimpleQuery("") - if !sent { - return err - } - if err != nil { - // shouldn't happen - panic(err) - } - return nil -} - -// Attempt to send a query on the connection. Returns an error if sending the -// query failed, and the caller should initiate closure of this connection. -// The caller must be holding senderLock (see acquireSenderLock and -// releaseSenderLock). -func (l *ListenerConn) sendSimpleQuery(q string) (err error) { - defer errRecoverNoErrBadConn(&err) - - // must set connection state before sending the query - if !l.setState(connStateExpectResponse) { - panic("two queries running at the same time") - } - - // Can't use l.cn.writeBuf here because it uses the scratch buffer which - // might get overwritten by listenerConnLoop. - b := &writeBuf{ - buf: []byte("Q\x00\x00\x00\x00"), - pos: 1, - } - b.string(q) - l.cn.send(b) - - return nil -} - -// ExecSimpleQuery executes a "simple query" (i.e. one with no bindable -// parameters) on the connection. The possible return values are: -// 1) "executed" is true; the query was executed to completion on the -// database server. If the query failed, err will be set to the error -// returned by the database, otherwise err will be nil. -// 2) If "executed" is false, the query could not be executed on the remote -// server. err will be non-nil. -// -// After a call to ExecSimpleQuery has returned an executed=false value, the -// connection has either been closed or will be closed shortly thereafter, and -// all subsequently executed queries will return an error. -func (l *ListenerConn) ExecSimpleQuery(q string) (executed bool, err error) { - if err = l.acquireSenderLock(); err != nil { - return false, err - } - defer l.releaseSenderLock() - - err = l.sendSimpleQuery(q) - if err != nil { - // We can't know what state the protocol is in, so we need to abandon - // this connection. - l.connectionLock.Lock() - // Set the error pointer if it hasn't been set already; see - // listenerConnMain. - if l.err == nil { - l.err = err - } - l.connectionLock.Unlock() - l.cn.c.Close() - return false, err - } - - // now we just wait for a reply.. - for { - m, ok := <-l.replyChan - if !ok { - // We lost the connection to server, don't bother waiting for a - // a response. err should have been set already. - l.connectionLock.Lock() - err := l.err - l.connectionLock.Unlock() - return false, err - } - switch m.typ { - case 'Z': - // sanity check - if m.err != nil { - panic("m.err != nil") - } - // done; err might or might not be set - return true, err - - case 'E': - // sanity check - if m.err == nil { - panic("m.err == nil") - } - // server responded with an error; ReadyForQuery to follow - err = m.err - - default: - return false, fmt.Errorf("unknown response for simple query: %q", m.typ) - } - } -} - -// Close closes the connection. -func (l *ListenerConn) Close() error { - l.connectionLock.Lock() - if l.err != nil { - l.connectionLock.Unlock() - return errListenerConnClosed - } - l.err = errListenerConnClosed - l.connectionLock.Unlock() - // We can't send anything on the connection without holding senderLock. - // Simply close the net.Conn to wake up everyone operating on it. - return l.cn.c.Close() -} - -// Err returns the reason the connection was closed. It is not safe to call -// this function until l.Notify has been closed. -func (l *ListenerConn) Err() error { - return l.err -} - -var errListenerClosed = errors.New("pq: Listener has been closed") - -// ErrChannelAlreadyOpen is returned from Listen when a channel is already -// open. -var ErrChannelAlreadyOpen = errors.New("pq: channel is already open") - -// ErrChannelNotOpen is returned from Unlisten when a channel is not open. -var ErrChannelNotOpen = errors.New("pq: channel is not open") - -// ListenerEventType is an enumeration of listener event types. -type ListenerEventType int - -const ( - // ListenerEventConnected is emitted only when the database connection - // has been initially initialized. The err argument of the callback - // will always be nil. - ListenerEventConnected ListenerEventType = iota - - // ListenerEventDisconnected is emitted after a database connection has - // been lost, either because of an error or because Close has been - // called. The err argument will be set to the reason the database - // connection was lost. - ListenerEventDisconnected - - // ListenerEventReconnected is emitted after a database connection has - // been re-established after connection loss. The err argument of the - // callback will always be nil. After this event has been emitted, a - // nil pq.Notification is sent on the Listener.Notify channel. - ListenerEventReconnected - - // ListenerEventConnectionAttemptFailed is emitted after a connection - // to the database was attempted, but failed. The err argument will be - // set to an error describing why the connection attempt did not - // succeed. - ListenerEventConnectionAttemptFailed -) - -// EventCallbackType is the event callback type. See also ListenerEventType -// constants' documentation. -type EventCallbackType func(event ListenerEventType, err error) - -// Listener provides an interface for listening to notifications from a -// PostgreSQL database. For general usage information, see section -// "Notifications". -// -// Listener can safely be used from concurrently running goroutines. -type Listener struct { - // Channel for receiving notifications from the database. In some cases a - // nil value will be sent. See section "Notifications" above. - Notify chan *Notification - - name string - minReconnectInterval time.Duration - maxReconnectInterval time.Duration - dialer Dialer - eventCallback EventCallbackType - - lock sync.Mutex - isClosed bool - reconnectCond *sync.Cond - cn *ListenerConn - connNotificationChan <-chan *Notification - channels map[string]struct{} -} - -// NewListener creates a new database connection dedicated to LISTEN / NOTIFY. -// -// name should be set to a connection string to be used to establish the -// database connection (see section "Connection String Parameters" above). -// -// minReconnectInterval controls the duration to wait before trying to -// re-establish the database connection after connection loss. After each -// consecutive failure this interval is doubled, until maxReconnectInterval is -// reached. Successfully completing the connection establishment procedure -// resets the interval back to minReconnectInterval. -// -// The last parameter eventCallback can be set to a function which will be -// called by the Listener when the state of the underlying database connection -// changes. This callback will be called by the goroutine which dispatches the -// notifications over the Notify channel, so you should try to avoid doing -// potentially time-consuming operations from the callback. -func NewListener(name string, - minReconnectInterval time.Duration, - maxReconnectInterval time.Duration, - eventCallback EventCallbackType) *Listener { - return NewDialListener(defaultDialer{}, name, minReconnectInterval, maxReconnectInterval, eventCallback) -} - -// NewDialListener is like NewListener but it takes a Dialer. -func NewDialListener(d Dialer, - name string, - minReconnectInterval time.Duration, - maxReconnectInterval time.Duration, - eventCallback EventCallbackType) *Listener { - - l := &Listener{ - name: name, - minReconnectInterval: minReconnectInterval, - maxReconnectInterval: maxReconnectInterval, - dialer: d, - eventCallback: eventCallback, - - channels: make(map[string]struct{}), - - Notify: make(chan *Notification, 32), - } - l.reconnectCond = sync.NewCond(&l.lock) - - go l.listenerMain() - - return l -} - -// NotificationChannel returns the notification channel for this listener. -// This is the same channel as Notify, and will not be recreated during the -// life time of the Listener. -func (l *Listener) NotificationChannel() <-chan *Notification { - return l.Notify -} - -// Listen starts listening for notifications on a channel. Calls to this -// function will block until an acknowledgement has been received from the -// server. Note that Listener automatically re-establishes the connection -// after connection loss, so this function may block indefinitely if the -// connection can not be re-established. -// -// Listen will only fail in three conditions: -// 1) The channel is already open. The returned error will be -// ErrChannelAlreadyOpen. -// 2) The query was executed on the remote server, but PostgreSQL returned an -// error message in response to the query. The returned error will be a -// pq.Error containing the information the server supplied. -// 3) Close is called on the Listener before the request could be completed. -// -// The channel name is case-sensitive. -func (l *Listener) Listen(channel string) error { - l.lock.Lock() - defer l.lock.Unlock() - - if l.isClosed { - return errListenerClosed - } - - // The server allows you to issue a LISTEN on a channel which is already - // open, but it seems useful to be able to detect this case to spot for - // mistakes in application logic. If the application genuinely does't - // care, it can check the exported error and ignore it. - _, exists := l.channels[channel] - if exists { - return ErrChannelAlreadyOpen - } - - if l.cn != nil { - // If gotResponse is true but error is set, the query was executed on - // the remote server, but resulted in an error. This should be - // relatively rare, so it's fine if we just pass the error to our - // caller. However, if gotResponse is false, we could not complete the - // query on the remote server and our underlying connection is about - // to go away, so we only add relname to l.channels, and wait for - // resync() to take care of the rest. - gotResponse, err := l.cn.Listen(channel) - if gotResponse && err != nil { - return err - } - } - - l.channels[channel] = struct{}{} - for l.cn == nil { - l.reconnectCond.Wait() - // we let go of the mutex for a while - if l.isClosed { - return errListenerClosed - } - } - - return nil -} - -// Unlisten removes a channel from the Listener's channel list. Returns -// ErrChannelNotOpen if the Listener is not listening on the specified channel. -// Returns immediately with no error if there is no connection. Note that you -// might still get notifications for this channel even after Unlisten has -// returned. -// -// The channel name is case-sensitive. -func (l *Listener) Unlisten(channel string) error { - l.lock.Lock() - defer l.lock.Unlock() - - if l.isClosed { - return errListenerClosed - } - - // Similarly to LISTEN, this is not an error in Postgres, but it seems - // useful to distinguish from the normal conditions. - _, exists := l.channels[channel] - if !exists { - return ErrChannelNotOpen - } - - if l.cn != nil { - // Similarly to Listen (see comment in that function), the caller - // should only be bothered with an error if it came from the backend as - // a response to our query. - gotResponse, err := l.cn.Unlisten(channel) - if gotResponse && err != nil { - return err - } - } - - // Don't bother waiting for resync if there's no connection. - delete(l.channels, channel) - return nil -} - -// UnlistenAll removes all channels from the Listener's channel list. Returns -// immediately with no error if there is no connection. Note that you might -// still get notifications for any of the deleted channels even after -// UnlistenAll has returned. -func (l *Listener) UnlistenAll() error { - l.lock.Lock() - defer l.lock.Unlock() - - if l.isClosed { - return errListenerClosed - } - - if l.cn != nil { - // Similarly to Listen (see comment in that function), the caller - // should only be bothered with an error if it came from the backend as - // a response to our query. - gotResponse, err := l.cn.UnlistenAll() - if gotResponse && err != nil { - return err - } - } - - // Don't bother waiting for resync if there's no connection. - l.channels = make(map[string]struct{}) - return nil -} - -// Ping the remote server to make sure it's alive. Non-nil return value means -// that there is no active connection. -func (l *Listener) Ping() error { - l.lock.Lock() - defer l.lock.Unlock() - - if l.isClosed { - return errListenerClosed - } - if l.cn == nil { - return errors.New("no connection") - } - - return l.cn.Ping() -} - -// Clean up after losing the server connection. Returns l.cn.Err(), which -// should have the reason the connection was lost. -func (l *Listener) disconnectCleanup() error { - l.lock.Lock() - defer l.lock.Unlock() - - // sanity check; can't look at Err() until the channel has been closed - select { - case _, ok := <-l.connNotificationChan: - if ok { - panic("connNotificationChan not closed") - } - default: - panic("connNotificationChan not closed") - } - - err := l.cn.Err() - l.cn.Close() - l.cn = nil - return err -} - -// Synchronize the list of channels we want to be listening on with the server -// after the connection has been established. -func (l *Listener) resync(cn *ListenerConn, notificationChan <-chan *Notification) error { - doneChan := make(chan error) - go func(notificationChan <-chan *Notification) { - for channel := range l.channels { - // If we got a response, return that error to our caller as it's - // going to be more descriptive than cn.Err(). - gotResponse, err := cn.Listen(channel) - if gotResponse && err != nil { - doneChan <- err - return - } - - // If we couldn't reach the server, wait for notificationChan to - // close and then return the error message from the connection, as - // per ListenerConn's interface. - if err != nil { - for range notificationChan { - } - doneChan <- cn.Err() - return - } - } - doneChan <- nil - }(notificationChan) - - // Ignore notifications while synchronization is going on to avoid - // deadlocks. We have to send a nil notification over Notify anyway as - // we can't possibly know which notifications (if any) were lost while - // the connection was down, so there's no reason to try and process - // these messages at all. - for { - select { - case _, ok := <-notificationChan: - if !ok { - notificationChan = nil - } - - case err := <-doneChan: - return err - } - } -} - -// caller should NOT be holding l.lock -func (l *Listener) closed() bool { - l.lock.Lock() - defer l.lock.Unlock() - - return l.isClosed -} - -func (l *Listener) connect() error { - notificationChan := make(chan *Notification, 32) - cn, err := newDialListenerConn(l.dialer, l.name, notificationChan) - if err != nil { - return err - } - - l.lock.Lock() - defer l.lock.Unlock() - - err = l.resync(cn, notificationChan) - if err != nil { - cn.Close() - return err - } - - l.cn = cn - l.connNotificationChan = notificationChan - l.reconnectCond.Broadcast() - - return nil -} - -// Close disconnects the Listener from the database and shuts it down. -// Subsequent calls to its methods will return an error. Close returns an -// error if the connection has already been closed. -func (l *Listener) Close() error { - l.lock.Lock() - defer l.lock.Unlock() - - if l.isClosed { - return errListenerClosed - } - - if l.cn != nil { - l.cn.Close() - } - l.isClosed = true - - // Unblock calls to Listen() - l.reconnectCond.Broadcast() - - return nil -} - -func (l *Listener) emitEvent(event ListenerEventType, err error) { - if l.eventCallback != nil { - l.eventCallback(event, err) - } -} - -// Main logic here: maintain a connection to the server when possible, wait -// for notifications and emit events. -func (l *Listener) listenerConnLoop() { - var nextReconnect time.Time - - reconnectInterval := l.minReconnectInterval - for { - for { - err := l.connect() - if err == nil { - break - } - - if l.closed() { - return - } - l.emitEvent(ListenerEventConnectionAttemptFailed, err) - - time.Sleep(reconnectInterval) - reconnectInterval *= 2 - if reconnectInterval > l.maxReconnectInterval { - reconnectInterval = l.maxReconnectInterval - } - } - - if nextReconnect.IsZero() { - l.emitEvent(ListenerEventConnected, nil) - } else { - l.emitEvent(ListenerEventReconnected, nil) - l.Notify <- nil - } - - reconnectInterval = l.minReconnectInterval - nextReconnect = time.Now().Add(reconnectInterval) - - for { - notification, ok := <-l.connNotificationChan - if !ok { - // lost connection, loop again - break - } - l.Notify <- notification - } - - err := l.disconnectCleanup() - if l.closed() { - return - } - l.emitEvent(ListenerEventDisconnected, err) - - time.Sleep(time.Until(nextReconnect)) - } -} - -func (l *Listener) listenerMain() { - l.listenerConnLoop() - close(l.Notify) -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/notify_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/notify_test.go deleted file mode 100644 index ed9807100..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/notify_test.go +++ /dev/null @@ -1,612 +0,0 @@ -package pq - -import ( - "database/sql" - "database/sql/driver" - "errors" - "fmt" - "io" - "os" - "runtime" - "sync" - "testing" - "time" -) - -var errNilNotification = errors.New("nil notification") - -func expectNotification(t *testing.T, ch <-chan *Notification, relname string, extra string) error { - select { - case n := <-ch: - if n == nil { - return errNilNotification - } - if n.Channel != relname || n.Extra != extra { - return fmt.Errorf("unexpected notification %v", n) - } - return nil - case <-time.After(1500 * time.Millisecond): - return fmt.Errorf("timeout") - } -} - -func expectNoNotification(t *testing.T, ch <-chan *Notification) error { - select { - case n := <-ch: - return fmt.Errorf("unexpected notification %v", n) - case <-time.After(100 * time.Millisecond): - return nil - } -} - -func expectEvent(t *testing.T, eventch <-chan ListenerEventType, et ListenerEventType) error { - select { - case e := <-eventch: - if e != et { - return fmt.Errorf("unexpected event %v", e) - } - return nil - case <-time.After(1500 * time.Millisecond): - panic("expectEvent timeout") - } -} - -func expectNoEvent(t *testing.T, eventch <-chan ListenerEventType) error { - select { - case e := <-eventch: - return fmt.Errorf("unexpected event %v", e) - case <-time.After(100 * time.Millisecond): - return nil - } -} - -func newTestListenerConn(t *testing.T) (*ListenerConn, <-chan *Notification) { - datname := os.Getenv("PGDATABASE") - sslmode := os.Getenv("PGSSLMODE") - - if datname == "" { - os.Setenv("PGDATABASE", "pqgotest") - } - - if sslmode == "" { - os.Setenv("PGSSLMODE", "disable") - } - - notificationChan := make(chan *Notification) - l, err := NewListenerConn("", notificationChan) - if err != nil { - t.Fatal(err) - } - - return l, notificationChan -} - -func TestNewListenerConn(t *testing.T) { - l, _ := newTestListenerConn(t) - - defer l.Close() -} - -func TestConnListen(t *testing.T) { - l, channel := newTestListenerConn(t) - - defer l.Close() - - db := openTestConn(t) - defer db.Close() - - ok, err := l.Listen("notify_test") - if !ok || err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_test") - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, channel, "notify_test", "") - if err != nil { - t.Fatal(err) - } -} - -func TestConnUnlisten(t *testing.T) { - l, channel := newTestListenerConn(t) - - defer l.Close() - - db := openTestConn(t) - defer db.Close() - - ok, err := l.Listen("notify_test") - if !ok || err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_test") - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, channel, "notify_test", "") - if err != nil { - t.Fatal(err) - } - - ok, err = l.Unlisten("notify_test") - if !ok || err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_test") - if err != nil { - t.Fatal(err) - } - - err = expectNoNotification(t, channel) - if err != nil { - t.Fatal(err) - } -} - -func TestConnUnlistenAll(t *testing.T) { - l, channel := newTestListenerConn(t) - - defer l.Close() - - db := openTestConn(t) - defer db.Close() - - ok, err := l.Listen("notify_test") - if !ok || err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_test") - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, channel, "notify_test", "") - if err != nil { - t.Fatal(err) - } - - ok, err = l.UnlistenAll() - if !ok || err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_test") - if err != nil { - t.Fatal(err) - } - - err = expectNoNotification(t, channel) - if err != nil { - t.Fatal(err) - } -} - -func TestConnClose(t *testing.T) { - l, _ := newTestListenerConn(t) - defer l.Close() - - err := l.Close() - if err != nil { - t.Fatal(err) - } - err = l.Close() - if err != errListenerConnClosed { - t.Fatalf("expected errListenerConnClosed; got %v", err) - } -} - -func TestConnPing(t *testing.T) { - l, _ := newTestListenerConn(t) - defer l.Close() - err := l.Ping() - if err != nil { - t.Fatal(err) - } - err = l.Close() - if err != nil { - t.Fatal(err) - } - err = l.Ping() - if err != errListenerConnClosed { - t.Fatalf("expected errListenerConnClosed; got %v", err) - } -} - -// Test for deadlock where a query fails while another one is queued -func TestConnExecDeadlock(t *testing.T) { - l, _ := newTestListenerConn(t) - defer l.Close() - - var wg sync.WaitGroup - wg.Add(2) - - go func() { - l.ExecSimpleQuery("SELECT pg_sleep(60)") - wg.Done() - }() - runtime.Gosched() - go func() { - l.ExecSimpleQuery("SELECT 1") - wg.Done() - }() - // give the two goroutines some time to get into position - runtime.Gosched() - // calls Close on the net.Conn; equivalent to a network failure - l.Close() - - defer time.AfterFunc(10*time.Second, func() { - panic("timed out") - }).Stop() - wg.Wait() -} - -// Test for ListenerConn being closed while a slow query is executing -func TestListenerConnCloseWhileQueryIsExecuting(t *testing.T) { - l, _ := newTestListenerConn(t) - defer l.Close() - - var wg sync.WaitGroup - wg.Add(1) - - go func() { - sent, err := l.ExecSimpleQuery("SELECT pg_sleep(60)") - if sent { - panic("expected sent=false") - } - // could be any of a number of errors - if err == nil { - panic("expected error") - } - wg.Done() - }() - // give the above goroutine some time to get into position - runtime.Gosched() - err := l.Close() - if err != nil { - t.Fatal(err) - } - - defer time.AfterFunc(10*time.Second, func() { - panic("timed out") - }).Stop() - wg.Wait() -} - -func TestNotifyExtra(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - if getServerVersion(t, db) < 90000 { - t.Skip("skipping NOTIFY payload test since the server does not appear to support it") - } - - l, channel := newTestListenerConn(t) - defer l.Close() - - ok, err := l.Listen("notify_test") - if !ok || err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_test, 'something'") - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, channel, "notify_test", "something") - if err != nil { - t.Fatal(err) - } -} - -// create a new test listener and also set the timeouts -func newTestListenerTimeout(t *testing.T, min time.Duration, max time.Duration) (*Listener, <-chan ListenerEventType) { - datname := os.Getenv("PGDATABASE") - sslmode := os.Getenv("PGSSLMODE") - - if datname == "" { - os.Setenv("PGDATABASE", "pqgotest") - } - - if sslmode == "" { - os.Setenv("PGSSLMODE", "disable") - } - - eventch := make(chan ListenerEventType, 16) - l := NewListener("", min, max, func(t ListenerEventType, err error) { eventch <- t }) - err := expectEvent(t, eventch, ListenerEventConnected) - if err != nil { - t.Fatal(err) - } - return l, eventch -} - -func newTestListener(t *testing.T) (*Listener, <-chan ListenerEventType) { - return newTestListenerTimeout(t, time.Hour, time.Hour) -} - -func TestListenerListen(t *testing.T) { - l, _ := newTestListener(t) - defer l.Close() - - db := openTestConn(t) - defer db.Close() - - err := l.Listen("notify_listen_test") - if err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_listen_test") - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, l.Notify, "notify_listen_test", "") - if err != nil { - t.Fatal(err) - } -} - -func TestListenerUnlisten(t *testing.T) { - l, _ := newTestListener(t) - defer l.Close() - - db := openTestConn(t) - defer db.Close() - - err := l.Listen("notify_listen_test") - if err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_listen_test") - if err != nil { - t.Fatal(err) - } - - err = l.Unlisten("notify_listen_test") - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, l.Notify, "notify_listen_test", "") - if err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_listen_test") - if err != nil { - t.Fatal(err) - } - - err = expectNoNotification(t, l.Notify) - if err != nil { - t.Fatal(err) - } -} - -func TestListenerUnlistenAll(t *testing.T) { - l, _ := newTestListener(t) - defer l.Close() - - db := openTestConn(t) - defer db.Close() - - err := l.Listen("notify_listen_test") - if err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_listen_test") - if err != nil { - t.Fatal(err) - } - - err = l.UnlistenAll() - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, l.Notify, "notify_listen_test", "") - if err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_listen_test") - if err != nil { - t.Fatal(err) - } - - err = expectNoNotification(t, l.Notify) - if err != nil { - t.Fatal(err) - } -} - -func TestListenerFailedQuery(t *testing.T) { - l, eventch := newTestListener(t) - defer l.Close() - - db := openTestConn(t) - defer db.Close() - - err := l.Listen("notify_listen_test") - if err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_listen_test") - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, l.Notify, "notify_listen_test", "") - if err != nil { - t.Fatal(err) - } - - // shouldn't cause a disconnect - ok, err := l.cn.ExecSimpleQuery("SELECT error") - if !ok { - t.Fatalf("could not send query to server: %v", err) - } - _, ok = err.(PGError) - if !ok { - t.Fatalf("unexpected error %v", err) - } - err = expectNoEvent(t, eventch) - if err != nil { - t.Fatal(err) - } - - // should still work - _, err = db.Exec("NOTIFY notify_listen_test") - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, l.Notify, "notify_listen_test", "") - if err != nil { - t.Fatal(err) - } -} - -func TestListenerReconnect(t *testing.T) { - l, eventch := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour) - defer l.Close() - - db := openTestConn(t) - defer db.Close() - - err := l.Listen("notify_listen_test") - if err != nil { - t.Fatal(err) - } - - _, err = db.Exec("NOTIFY notify_listen_test") - if err != nil { - t.Fatal(err) - } - - err = expectNotification(t, l.Notify, "notify_listen_test", "") - if err != nil { - t.Fatal(err) - } - - // kill the connection and make sure it comes back up - ok, err := l.cn.ExecSimpleQuery("SELECT pg_terminate_backend(pg_backend_pid())") - if ok { - t.Fatalf("could not kill the connection: %v", err) - } - if err != io.EOF { - t.Fatalf("unexpected error %v", err) - } - err = expectEvent(t, eventch, ListenerEventDisconnected) - if err != nil { - t.Fatal(err) - } - err = expectEvent(t, eventch, ListenerEventReconnected) - if err != nil { - t.Fatal(err) - } - - // should still work - _, err = db.Exec("NOTIFY notify_listen_test") - if err != nil { - t.Fatal(err) - } - - // should get nil after Reconnected - err = expectNotification(t, l.Notify, "", "") - if err != errNilNotification { - t.Fatal(err) - } - - err = expectNotification(t, l.Notify, "notify_listen_test", "") - if err != nil { - t.Fatal(err) - } -} - -func TestListenerClose(t *testing.T) { - l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour) - defer l.Close() - - err := l.Close() - if err != nil { - t.Fatal(err) - } - err = l.Close() - if err != errListenerClosed { - t.Fatalf("expected errListenerClosed; got %v", err) - } -} - -func TestListenerPing(t *testing.T) { - l, _ := newTestListenerTimeout(t, 20*time.Millisecond, time.Hour) - defer l.Close() - - err := l.Ping() - if err != nil { - t.Fatal(err) - } - - err = l.Close() - if err != nil { - t.Fatal(err) - } - - err = l.Ping() - if err != errListenerClosed { - t.Fatalf("expected errListenerClosed; got %v", err) - } -} - -func TestConnectorWithNotificationHandler_Simple(t *testing.T) { - b, err := NewConnector("") - if err != nil { - t.Fatal(err) - } - var notification *Notification - // Make connector w/ handler to set the local var - c := ConnectorWithNotificationHandler(b, func(n *Notification) { notification = n }) - sendNotification(c, t, "Test notification #1") - if notification == nil || notification.Extra != "Test notification #1" { - t.Fatalf("Expected notification w/ message, got %v", notification) - } - // Unset the handler on the same connector - prevC := c - if c = ConnectorWithNotificationHandler(c, nil); c != prevC { - t.Fatalf("Expected to not create new connector but did") - } - sendNotification(c, t, "Test notification #2") - if notification == nil || notification.Extra != "Test notification #1" { - t.Fatalf("Expected notification to not change, got %v", notification) - } - // Set it back on the same connector - if c = ConnectorWithNotificationHandler(c, func(n *Notification) { notification = n }); c != prevC { - t.Fatal("Expected to not create new connector but did") - } - sendNotification(c, t, "Test notification #3") - if notification == nil || notification.Extra != "Test notification #3" { - t.Fatalf("Expected notification w/ message, got %v", notification) - } -} - -func sendNotification(c driver.Connector, t *testing.T, escapedNotification string) { - db := sql.OpenDB(c) - defer db.Close() - sql := fmt.Sprintf("LISTEN foo; NOTIFY foo, '%s';", escapedNotification) - if _, err := db.Exec(sql); err != nil { - t.Fatal(err) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/oid/doc.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/oid/doc.go deleted file mode 100644 index caaede248..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/oid/doc.go +++ /dev/null @@ -1,6 +0,0 @@ -// Package oid contains OID constants -// as defined by the Postgres server. -package oid - -// Oid is a Postgres Object ID. -type Oid uint32 diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/oid/gen.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/oid/gen.go deleted file mode 100644 index 29a8de8ba..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/oid/gen.go +++ /dev/null @@ -1,94 +0,0 @@ -//go:build ignore -// +build ignore - -// Generate the table of OID values -// Run with 'go run gen.go'. -package main - -import ( - "database/sql" - "fmt" - "log" - "os" - "os/exec" - "strings" - - _ "github.com/lib/pq" -) - -// OID represent a postgres Object Identifier Type. -type OID struct { - ID int - Type string -} - -// Name returns an upper case version of the oid type. -func (o OID) Name() string { - return strings.ToUpper(o.Type) -} - -func main() { - datname := os.Getenv("PGDATABASE") - sslmode := os.Getenv("PGSSLMODE") - - if datname == "" { - os.Setenv("PGDATABASE", "pqgotest") - } - - if sslmode == "" { - os.Setenv("PGSSLMODE", "disable") - } - - db, err := sql.Open("postgres", "") - if err != nil { - log.Fatal(err) - } - rows, err := db.Query(` - SELECT typname, oid - FROM pg_type WHERE oid < 10000 - ORDER BY oid; - `) - if err != nil { - log.Fatal(err) - } - oids := make([]*OID, 0) - for rows.Next() { - var oid OID - if err = rows.Scan(&oid.Type, &oid.ID); err != nil { - log.Fatal(err) - } - oids = append(oids, &oid) - } - if err = rows.Err(); err != nil { - log.Fatal(err) - } - cmd := exec.Command("gofmt") - cmd.Stderr = os.Stderr - w, err := cmd.StdinPipe() - if err != nil { - log.Fatal(err) - } - f, err := os.Create("types.go") - if err != nil { - log.Fatal(err) - } - cmd.Stdout = f - err = cmd.Start() - if err != nil { - log.Fatal(err) - } - fmt.Fprintln(w, "// Code generated by gen.go. DO NOT EDIT.") - fmt.Fprintln(w, "\npackage oid") - fmt.Fprintln(w, "const (") - for _, oid := range oids { - fmt.Fprintf(w, "T_%s Oid = %d\n", oid.Type, oid.ID) - } - fmt.Fprintln(w, ")") - fmt.Fprintln(w, "var TypeName = map[Oid]string{") - for _, oid := range oids { - fmt.Fprintf(w, "T_%s: \"%s\",\n", oid.Type, oid.Name()) - } - fmt.Fprintln(w, "}") - w.Close() - cmd.Wait() -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/oid/types.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/oid/types.go deleted file mode 100644 index ecc84c2c8..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/oid/types.go +++ /dev/null @@ -1,343 +0,0 @@ -// Code generated by gen.go. DO NOT EDIT. - -package oid - -const ( - T_bool Oid = 16 - T_bytea Oid = 17 - T_char Oid = 18 - T_name Oid = 19 - T_int8 Oid = 20 - T_int2 Oid = 21 - T_int2vector Oid = 22 - T_int4 Oid = 23 - T_regproc Oid = 24 - T_text Oid = 25 - T_oid Oid = 26 - T_tid Oid = 27 - T_xid Oid = 28 - T_cid Oid = 29 - T_oidvector Oid = 30 - T_pg_ddl_command Oid = 32 - T_pg_type Oid = 71 - T_pg_attribute Oid = 75 - T_pg_proc Oid = 81 - T_pg_class Oid = 83 - T_json Oid = 114 - T_xml Oid = 142 - T__xml Oid = 143 - T_pg_node_tree Oid = 194 - T__json Oid = 199 - T_smgr Oid = 210 - T_index_am_handler Oid = 325 - T_point Oid = 600 - T_lseg Oid = 601 - T_path Oid = 602 - T_box Oid = 603 - T_polygon Oid = 604 - T_line Oid = 628 - T__line Oid = 629 - T_cidr Oid = 650 - T__cidr Oid = 651 - T_float4 Oid = 700 - T_float8 Oid = 701 - T_abstime Oid = 702 - T_reltime Oid = 703 - T_tinterval Oid = 704 - T_unknown Oid = 705 - T_circle Oid = 718 - T__circle Oid = 719 - T_money Oid = 790 - T__money Oid = 791 - T_macaddr Oid = 829 - T_inet Oid = 869 - T__bool Oid = 1000 - T__bytea Oid = 1001 - T__char Oid = 1002 - T__name Oid = 1003 - T__int2 Oid = 1005 - T__int2vector Oid = 1006 - T__int4 Oid = 1007 - T__regproc Oid = 1008 - T__text Oid = 1009 - T__tid Oid = 1010 - T__xid Oid = 1011 - T__cid Oid = 1012 - T__oidvector Oid = 1013 - T__bpchar Oid = 1014 - T__varchar Oid = 1015 - T__int8 Oid = 1016 - T__point Oid = 1017 - T__lseg Oid = 1018 - T__path Oid = 1019 - T__box Oid = 1020 - T__float4 Oid = 1021 - T__float8 Oid = 1022 - T__abstime Oid = 1023 - T__reltime Oid = 1024 - T__tinterval Oid = 1025 - T__polygon Oid = 1027 - T__oid Oid = 1028 - T_aclitem Oid = 1033 - T__aclitem Oid = 1034 - T__macaddr Oid = 1040 - T__inet Oid = 1041 - T_bpchar Oid = 1042 - T_varchar Oid = 1043 - T_date Oid = 1082 - T_time Oid = 1083 - T_timestamp Oid = 1114 - T__timestamp Oid = 1115 - T__date Oid = 1182 - T__time Oid = 1183 - T_timestamptz Oid = 1184 - T__timestamptz Oid = 1185 - T_interval Oid = 1186 - T__interval Oid = 1187 - T__numeric Oid = 1231 - T_pg_database Oid = 1248 - T__cstring Oid = 1263 - T_timetz Oid = 1266 - T__timetz Oid = 1270 - T_bit Oid = 1560 - T__bit Oid = 1561 - T_varbit Oid = 1562 - T__varbit Oid = 1563 - T_numeric Oid = 1700 - T_refcursor Oid = 1790 - T__refcursor Oid = 2201 - T_regprocedure Oid = 2202 - T_regoper Oid = 2203 - T_regoperator Oid = 2204 - T_regclass Oid = 2205 - T_regtype Oid = 2206 - T__regprocedure Oid = 2207 - T__regoper Oid = 2208 - T__regoperator Oid = 2209 - T__regclass Oid = 2210 - T__regtype Oid = 2211 - T_record Oid = 2249 - T_cstring Oid = 2275 - T_any Oid = 2276 - T_anyarray Oid = 2277 - T_void Oid = 2278 - T_trigger Oid = 2279 - T_language_handler Oid = 2280 - T_internal Oid = 2281 - T_opaque Oid = 2282 - T_anyelement Oid = 2283 - T__record Oid = 2287 - T_anynonarray Oid = 2776 - T_pg_authid Oid = 2842 - T_pg_auth_members Oid = 2843 - T__txid_snapshot Oid = 2949 - T_uuid Oid = 2950 - T__uuid Oid = 2951 - T_txid_snapshot Oid = 2970 - T_fdw_handler Oid = 3115 - T_pg_lsn Oid = 3220 - T__pg_lsn Oid = 3221 - T_tsm_handler Oid = 3310 - T_anyenum Oid = 3500 - T_tsvector Oid = 3614 - T_tsquery Oid = 3615 - T_gtsvector Oid = 3642 - T__tsvector Oid = 3643 - T__gtsvector Oid = 3644 - T__tsquery Oid = 3645 - T_regconfig Oid = 3734 - T__regconfig Oid = 3735 - T_regdictionary Oid = 3769 - T__regdictionary Oid = 3770 - T_jsonb Oid = 3802 - T__jsonb Oid = 3807 - T_anyrange Oid = 3831 - T_event_trigger Oid = 3838 - T_int4range Oid = 3904 - T__int4range Oid = 3905 - T_numrange Oid = 3906 - T__numrange Oid = 3907 - T_tsrange Oid = 3908 - T__tsrange Oid = 3909 - T_tstzrange Oid = 3910 - T__tstzrange Oid = 3911 - T_daterange Oid = 3912 - T__daterange Oid = 3913 - T_int8range Oid = 3926 - T__int8range Oid = 3927 - T_pg_shseclabel Oid = 4066 - T_regnamespace Oid = 4089 - T__regnamespace Oid = 4090 - T_regrole Oid = 4096 - T__regrole Oid = 4097 -) - -var TypeName = map[Oid]string{ - T_bool: "BOOL", - T_bytea: "BYTEA", - T_char: "CHAR", - T_name: "NAME", - T_int8: "INT8", - T_int2: "INT2", - T_int2vector: "INT2VECTOR", - T_int4: "INT4", - T_regproc: "REGPROC", - T_text: "TEXT", - T_oid: "OID", - T_tid: "TID", - T_xid: "XID", - T_cid: "CID", - T_oidvector: "OIDVECTOR", - T_pg_ddl_command: "PG_DDL_COMMAND", - T_pg_type: "PG_TYPE", - T_pg_attribute: "PG_ATTRIBUTE", - T_pg_proc: "PG_PROC", - T_pg_class: "PG_CLASS", - T_json: "JSON", - T_xml: "XML", - T__xml: "_XML", - T_pg_node_tree: "PG_NODE_TREE", - T__json: "_JSON", - T_smgr: "SMGR", - T_index_am_handler: "INDEX_AM_HANDLER", - T_point: "POINT", - T_lseg: "LSEG", - T_path: "PATH", - T_box: "BOX", - T_polygon: "POLYGON", - T_line: "LINE", - T__line: "_LINE", - T_cidr: "CIDR", - T__cidr: "_CIDR", - T_float4: "FLOAT4", - T_float8: "FLOAT8", - T_abstime: "ABSTIME", - T_reltime: "RELTIME", - T_tinterval: "TINTERVAL", - T_unknown: "UNKNOWN", - T_circle: "CIRCLE", - T__circle: "_CIRCLE", - T_money: "MONEY", - T__money: "_MONEY", - T_macaddr: "MACADDR", - T_inet: "INET", - T__bool: "_BOOL", - T__bytea: "_BYTEA", - T__char: "_CHAR", - T__name: "_NAME", - T__int2: "_INT2", - T__int2vector: "_INT2VECTOR", - T__int4: "_INT4", - T__regproc: "_REGPROC", - T__text: "_TEXT", - T__tid: "_TID", - T__xid: "_XID", - T__cid: "_CID", - T__oidvector: "_OIDVECTOR", - T__bpchar: "_BPCHAR", - T__varchar: "_VARCHAR", - T__int8: "_INT8", - T__point: "_POINT", - T__lseg: "_LSEG", - T__path: "_PATH", - T__box: "_BOX", - T__float4: "_FLOAT4", - T__float8: "_FLOAT8", - T__abstime: "_ABSTIME", - T__reltime: "_RELTIME", - T__tinterval: "_TINTERVAL", - T__polygon: "_POLYGON", - T__oid: "_OID", - T_aclitem: "ACLITEM", - T__aclitem: "_ACLITEM", - T__macaddr: "_MACADDR", - T__inet: "_INET", - T_bpchar: "BPCHAR", - T_varchar: "VARCHAR", - T_date: "DATE", - T_time: "TIME", - T_timestamp: "TIMESTAMP", - T__timestamp: "_TIMESTAMP", - T__date: "_DATE", - T__time: "_TIME", - T_timestamptz: "TIMESTAMPTZ", - T__timestamptz: "_TIMESTAMPTZ", - T_interval: "INTERVAL", - T__interval: "_INTERVAL", - T__numeric: "_NUMERIC", - T_pg_database: "PG_DATABASE", - T__cstring: "_CSTRING", - T_timetz: "TIMETZ", - T__timetz: "_TIMETZ", - T_bit: "BIT", - T__bit: "_BIT", - T_varbit: "VARBIT", - T__varbit: "_VARBIT", - T_numeric: "NUMERIC", - T_refcursor: "REFCURSOR", - T__refcursor: "_REFCURSOR", - T_regprocedure: "REGPROCEDURE", - T_regoper: "REGOPER", - T_regoperator: "REGOPERATOR", - T_regclass: "REGCLASS", - T_regtype: "REGTYPE", - T__regprocedure: "_REGPROCEDURE", - T__regoper: "_REGOPER", - T__regoperator: "_REGOPERATOR", - T__regclass: "_REGCLASS", - T__regtype: "_REGTYPE", - T_record: "RECORD", - T_cstring: "CSTRING", - T_any: "ANY", - T_anyarray: "ANYARRAY", - T_void: "VOID", - T_trigger: "TRIGGER", - T_language_handler: "LANGUAGE_HANDLER", - T_internal: "INTERNAL", - T_opaque: "OPAQUE", - T_anyelement: "ANYELEMENT", - T__record: "_RECORD", - T_anynonarray: "ANYNONARRAY", - T_pg_authid: "PG_AUTHID", - T_pg_auth_members: "PG_AUTH_MEMBERS", - T__txid_snapshot: "_TXID_SNAPSHOT", - T_uuid: "UUID", - T__uuid: "_UUID", - T_txid_snapshot: "TXID_SNAPSHOT", - T_fdw_handler: "FDW_HANDLER", - T_pg_lsn: "PG_LSN", - T__pg_lsn: "_PG_LSN", - T_tsm_handler: "TSM_HANDLER", - T_anyenum: "ANYENUM", - T_tsvector: "TSVECTOR", - T_tsquery: "TSQUERY", - T_gtsvector: "GTSVECTOR", - T__tsvector: "_TSVECTOR", - T__gtsvector: "_GTSVECTOR", - T__tsquery: "_TSQUERY", - T_regconfig: "REGCONFIG", - T__regconfig: "_REGCONFIG", - T_regdictionary: "REGDICTIONARY", - T__regdictionary: "_REGDICTIONARY", - T_jsonb: "JSONB", - T__jsonb: "_JSONB", - T_anyrange: "ANYRANGE", - T_event_trigger: "EVENT_TRIGGER", - T_int4range: "INT4RANGE", - T__int4range: "_INT4RANGE", - T_numrange: "NUMRANGE", - T__numrange: "_NUMRANGE", - T_tsrange: "TSRANGE", - T__tsrange: "_TSRANGE", - T_tstzrange: "TSTZRANGE", - T__tstzrange: "_TSTZRANGE", - T_daterange: "DATERANGE", - T__daterange: "_DATERANGE", - T_int8range: "INT8RANGE", - T__int8range: "_INT8RANGE", - T_pg_shseclabel: "PG_SHSECLABEL", - T_regnamespace: "REGNAMESPACE", - T__regnamespace: "_REGNAMESPACE", - T_regrole: "REGROLE", - T__regrole: "_REGROLE", -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/rows.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/rows.go deleted file mode 100644 index c6aa5b9a3..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/rows.go +++ /dev/null @@ -1,93 +0,0 @@ -package pq - -import ( - "math" - "reflect" - "time" - - "github.com/lib/pq/oid" -) - -const headerSize = 4 - -type fieldDesc struct { - // The object ID of the data type. - OID oid.Oid - // The data type size (see pg_type.typlen). - // Note that negative values denote variable-width types. - Len int - // The type modifier (see pg_attribute.atttypmod). - // The meaning of the modifier is type-specific. - Mod int -} - -func (fd fieldDesc) Type() reflect.Type { - switch fd.OID { - case oid.T_int8: - return reflect.TypeOf(int64(0)) - case oid.T_int4: - return reflect.TypeOf(int32(0)) - case oid.T_int2: - return reflect.TypeOf(int16(0)) - case oid.T_varchar, oid.T_text: - return reflect.TypeOf("") - case oid.T_bool: - return reflect.TypeOf(false) - case oid.T_date, oid.T_time, oid.T_timetz, oid.T_timestamp, oid.T_timestamptz: - return reflect.TypeOf(time.Time{}) - case oid.T_bytea: - return reflect.TypeOf([]byte(nil)) - default: - return reflect.TypeOf(new(interface{})).Elem() - } -} - -func (fd fieldDesc) Name() string { - return oid.TypeName[fd.OID] -} - -func (fd fieldDesc) Length() (length int64, ok bool) { - switch fd.OID { - case oid.T_text, oid.T_bytea: - return math.MaxInt64, true - case oid.T_varchar, oid.T_bpchar: - return int64(fd.Mod - headerSize), true - default: - return 0, false - } -} - -func (fd fieldDesc) PrecisionScale() (precision, scale int64, ok bool) { - switch fd.OID { - case oid.T_numeric, oid.T__numeric: - mod := fd.Mod - headerSize - precision = int64((mod >> 16) & 0xffff) - scale = int64(mod & 0xffff) - return precision, scale, true - default: - return 0, 0, false - } -} - -// ColumnTypeScanType returns the value type that can be used to scan types into. -func (rs *rows) ColumnTypeScanType(index int) reflect.Type { - return rs.colTyps[index].Type() -} - -// ColumnTypeDatabaseTypeName return the database system type name. -func (rs *rows) ColumnTypeDatabaseTypeName(index int) string { - return rs.colTyps[index].Name() -} - -// ColumnTypeLength returns the length of the column type if the column is a -// variable length type. If the column is not a variable length type ok -// should return false. -func (rs *rows) ColumnTypeLength(index int) (length int64, ok bool) { - return rs.colTyps[index].Length() -} - -// ColumnTypePrecisionScale should return the precision and scale for decimal -// types. If not applicable, ok should be false. -func (rs *rows) ColumnTypePrecisionScale(index int) (precision, scale int64, ok bool) { - return rs.colTyps[index].PrecisionScale() -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/rows_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/rows_test.go deleted file mode 100644 index b3420a299..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/rows_test.go +++ /dev/null @@ -1,218 +0,0 @@ -package pq - -import ( - "math" - "reflect" - "testing" - - "github.com/lib/pq/oid" -) - -func TestDataTypeName(t *testing.T) { - tts := []struct { - typ oid.Oid - name string - }{ - {oid.T_int8, "INT8"}, - {oid.T_int4, "INT4"}, - {oid.T_int2, "INT2"}, - {oid.T_varchar, "VARCHAR"}, - {oid.T_text, "TEXT"}, - {oid.T_bool, "BOOL"}, - {oid.T_numeric, "NUMERIC"}, - {oid.T_date, "DATE"}, - {oid.T_time, "TIME"}, - {oid.T_timetz, "TIMETZ"}, - {oid.T_timestamp, "TIMESTAMP"}, - {oid.T_timestamptz, "TIMESTAMPTZ"}, - {oid.T_bytea, "BYTEA"}, - } - - for i, tt := range tts { - dt := fieldDesc{OID: tt.typ} - if name := dt.Name(); name != tt.name { - t.Errorf("(%d) got: %s want: %s", i, name, tt.name) - } - } -} - -func TestDataType(t *testing.T) { - tts := []struct { - typ oid.Oid - kind reflect.Kind - }{ - {oid.T_int8, reflect.Int64}, - {oid.T_int4, reflect.Int32}, - {oid.T_int2, reflect.Int16}, - {oid.T_varchar, reflect.String}, - {oid.T_text, reflect.String}, - {oid.T_bool, reflect.Bool}, - {oid.T_date, reflect.Struct}, - {oid.T_time, reflect.Struct}, - {oid.T_timetz, reflect.Struct}, - {oid.T_timestamp, reflect.Struct}, - {oid.T_timestamptz, reflect.Struct}, - {oid.T_bytea, reflect.Slice}, - } - - for i, tt := range tts { - dt := fieldDesc{OID: tt.typ} - if kind := dt.Type().Kind(); kind != tt.kind { - t.Errorf("(%d) got: %s want: %s", i, kind, tt.kind) - } - } -} - -func TestDataTypeLength(t *testing.T) { - tts := []struct { - typ oid.Oid - len int - mod int - length int64 - ok bool - }{ - {oid.T_int4, 0, -1, 0, false}, - {oid.T_varchar, 65535, 9, 5, true}, - {oid.T_text, 65535, -1, math.MaxInt64, true}, - {oid.T_bytea, 65535, -1, math.MaxInt64, true}, - } - - for i, tt := range tts { - dt := fieldDesc{OID: tt.typ, Len: tt.len, Mod: tt.mod} - if l, k := dt.Length(); k != tt.ok || l != tt.length { - t.Errorf("(%d) got: %d, %t want: %d, %t", i, l, k, tt.length, tt.ok) - } - } -} - -func TestDataTypePrecisionScale(t *testing.T) { - tts := []struct { - typ oid.Oid - mod int - precision, scale int64 - ok bool - }{ - {oid.T_int4, -1, 0, 0, false}, - {oid.T_numeric, 589830, 9, 2, true}, - {oid.T_text, -1, 0, 0, false}, - } - - for i, tt := range tts { - dt := fieldDesc{OID: tt.typ, Mod: tt.mod} - p, s, k := dt.PrecisionScale() - if k != tt.ok { - t.Errorf("(%d) got: %t want: %t", i, k, tt.ok) - } - if p != tt.precision { - t.Errorf("(%d) wrong precision got: %d want: %d", i, p, tt.precision) - } - if s != tt.scale { - t.Errorf("(%d) wrong scale got: %d want: %d", i, s, tt.scale) - } - } -} - -func TestRowsColumnTypes(t *testing.T) { - columnTypesTests := []struct { - Name string - TypeName string - Length struct { - Len int64 - OK bool - } - DecimalSize struct { - Precision int64 - Scale int64 - OK bool - } - ScanType reflect.Type - }{ - { - Name: "a", - TypeName: "INT4", - Length: struct { - Len int64 - OK bool - }{ - Len: 0, - OK: false, - }, - DecimalSize: struct { - Precision int64 - Scale int64 - OK bool - }{ - Precision: 0, - Scale: 0, - OK: false, - }, - ScanType: reflect.TypeOf(int32(0)), - }, { - Name: "bar", - TypeName: "TEXT", - Length: struct { - Len int64 - OK bool - }{ - Len: math.MaxInt64, - OK: true, - }, - DecimalSize: struct { - Precision int64 - Scale int64 - OK bool - }{ - Precision: 0, - Scale: 0, - OK: false, - }, - ScanType: reflect.TypeOf(""), - }, - } - - db := openTestConn(t) - defer db.Close() - - rows, err := db.Query("SELECT 1 AS a, text 'bar' AS bar, 1.28::numeric(9, 2) AS dec") - if err != nil { - t.Fatal(err) - } - - columns, err := rows.ColumnTypes() - if err != nil { - t.Fatal(err) - } - if len(columns) != 3 { - t.Errorf("expected 3 columns found %d", len(columns)) - } - - for i, tt := range columnTypesTests { - c := columns[i] - if c.Name() != tt.Name { - t.Errorf("(%d) got: %s, want: %s", i, c.Name(), tt.Name) - } - if c.DatabaseTypeName() != tt.TypeName { - t.Errorf("(%d) got: %s, want: %s", i, c.DatabaseTypeName(), tt.TypeName) - } - l, ok := c.Length() - if l != tt.Length.Len { - t.Errorf("(%d) got: %d, want: %d", i, l, tt.Length.Len) - } - if ok != tt.Length.OK { - t.Errorf("(%d) got: %t, want: %t", i, ok, tt.Length.OK) - } - p, s, ok := c.DecimalSize() - if p != tt.DecimalSize.Precision { - t.Errorf("(%d) got: %d, want: %d", i, p, tt.DecimalSize.Precision) - } - if s != tt.DecimalSize.Scale { - t.Errorf("(%d) got: %d, want: %d", i, s, tt.DecimalSize.Scale) - } - if ok != tt.DecimalSize.OK { - t.Errorf("(%d) got: %t, want: %t", i, ok, tt.DecimalSize.OK) - } - if c.ScanType() != tt.ScanType { - t.Errorf("(%d) got: %v, want: %v", i, c.ScanType(), tt.ScanType) - } - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/scram/scram.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/scram/scram.go deleted file mode 100644 index 477216b60..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/scram/scram.go +++ /dev/null @@ -1,264 +0,0 @@ -// Copyright (c) 2014 - Gustavo Niemeyer -// -// All rights reserved. -// -// Redistribution and use in source and binary forms, with or without -// modification, are permitted provided that the following conditions are met: -// -// 1. Redistributions of source code must retain the above copyright notice, this -// list of conditions and the following disclaimer. -// 2. Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimer in the documentation -// and/or other materials provided with the distribution. -// -// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -// ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND -// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -// Package scram implements a SCRAM-{SHA-1,etc} client per RFC5802. -// -// http://tools.ietf.org/html/rfc5802 -// -package scram - -import ( - "bytes" - "crypto/hmac" - "crypto/rand" - "encoding/base64" - "fmt" - "hash" - "strconv" - "strings" -) - -// Client implements a SCRAM-* client (SCRAM-SHA-1, SCRAM-SHA-256, etc). -// -// A Client may be used within a SASL conversation with logic resembling: -// -// var in []byte -// var client = scram.NewClient(sha1.New, user, pass) -// for client.Step(in) { -// out := client.Out() -// // send out to server -// in := serverOut -// } -// if client.Err() != nil { -// // auth failed -// } -// -type Client struct { - newHash func() hash.Hash - - user string - pass string - step int - out bytes.Buffer - err error - - clientNonce []byte - serverNonce []byte - saltedPass []byte - authMsg bytes.Buffer -} - -// NewClient returns a new SCRAM-* client with the provided hash algorithm. -// -// For SCRAM-SHA-256, for example, use: -// -// client := scram.NewClient(sha256.New, user, pass) -// -func NewClient(newHash func() hash.Hash, user, pass string) *Client { - c := &Client{ - newHash: newHash, - user: user, - pass: pass, - } - c.out.Grow(256) - c.authMsg.Grow(256) - return c -} - -// Out returns the data to be sent to the server in the current step. -func (c *Client) Out() []byte { - if c.out.Len() == 0 { - return nil - } - return c.out.Bytes() -} - -// Err returns the error that occurred, or nil if there were no errors. -func (c *Client) Err() error { - return c.err -} - -// SetNonce sets the client nonce to the provided value. -// If not set, the nonce is generated automatically out of crypto/rand on the first step. -func (c *Client) SetNonce(nonce []byte) { - c.clientNonce = nonce -} - -var escaper = strings.NewReplacer("=", "=3D", ",", "=2C") - -// Step processes the incoming data from the server and makes the -// next round of data for the server available via Client.Out. -// Step returns false if there are no errors and more data is -// still expected. -func (c *Client) Step(in []byte) bool { - c.out.Reset() - if c.step > 2 || c.err != nil { - return false - } - c.step++ - switch c.step { - case 1: - c.err = c.step1(in) - case 2: - c.err = c.step2(in) - case 3: - c.err = c.step3(in) - } - return c.step > 2 || c.err != nil -} - -func (c *Client) step1(in []byte) error { - if len(c.clientNonce) == 0 { - const nonceLen = 16 - buf := make([]byte, nonceLen+b64.EncodedLen(nonceLen)) - if _, err := rand.Read(buf[:nonceLen]); err != nil { - return fmt.Errorf("cannot read random SCRAM-SHA-256 nonce from operating system: %v", err) - } - c.clientNonce = buf[nonceLen:] - b64.Encode(c.clientNonce, buf[:nonceLen]) - } - c.authMsg.WriteString("n=") - escaper.WriteString(&c.authMsg, c.user) - c.authMsg.WriteString(",r=") - c.authMsg.Write(c.clientNonce) - - c.out.WriteString("n,,") - c.out.Write(c.authMsg.Bytes()) - return nil -} - -var b64 = base64.StdEncoding - -func (c *Client) step2(in []byte) error { - c.authMsg.WriteByte(',') - c.authMsg.Write(in) - - fields := bytes.Split(in, []byte(",")) - if len(fields) != 3 { - return fmt.Errorf("expected 3 fields in first SCRAM-SHA-256 server message, got %d: %q", len(fields), in) - } - if !bytes.HasPrefix(fields[0], []byte("r=")) || len(fields[0]) < 2 { - return fmt.Errorf("server sent an invalid SCRAM-SHA-256 nonce: %q", fields[0]) - } - if !bytes.HasPrefix(fields[1], []byte("s=")) || len(fields[1]) < 6 { - return fmt.Errorf("server sent an invalid SCRAM-SHA-256 salt: %q", fields[1]) - } - if !bytes.HasPrefix(fields[2], []byte("i=")) || len(fields[2]) < 6 { - return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2]) - } - - c.serverNonce = fields[0][2:] - if !bytes.HasPrefix(c.serverNonce, c.clientNonce) { - return fmt.Errorf("server SCRAM-SHA-256 nonce is not prefixed by client nonce: got %q, want %q+\"...\"", c.serverNonce, c.clientNonce) - } - - salt := make([]byte, b64.DecodedLen(len(fields[1][2:]))) - n, err := b64.Decode(salt, fields[1][2:]) - if err != nil { - return fmt.Errorf("cannot decode SCRAM-SHA-256 salt sent by server: %q", fields[1]) - } - salt = salt[:n] - iterCount, err := strconv.Atoi(string(fields[2][2:])) - if err != nil { - return fmt.Errorf("server sent an invalid SCRAM-SHA-256 iteration count: %q", fields[2]) - } - c.saltPassword(salt, iterCount) - - c.authMsg.WriteString(",c=biws,r=") - c.authMsg.Write(c.serverNonce) - - c.out.WriteString("c=biws,r=") - c.out.Write(c.serverNonce) - c.out.WriteString(",p=") - c.out.Write(c.clientProof()) - return nil -} - -func (c *Client) step3(in []byte) error { - var isv, ise bool - var fields = bytes.Split(in, []byte(",")) - if len(fields) == 1 { - isv = bytes.HasPrefix(fields[0], []byte("v=")) - ise = bytes.HasPrefix(fields[0], []byte("e=")) - } - if ise { - return fmt.Errorf("SCRAM-SHA-256 authentication error: %s", fields[0][2:]) - } else if !isv { - return fmt.Errorf("unsupported SCRAM-SHA-256 final message from server: %q", in) - } - if !bytes.Equal(c.serverSignature(), fields[0][2:]) { - return fmt.Errorf("cannot authenticate SCRAM-SHA-256 server signature: %q", fields[0][2:]) - } - return nil -} - -func (c *Client) saltPassword(salt []byte, iterCount int) { - mac := hmac.New(c.newHash, []byte(c.pass)) - mac.Write(salt) - mac.Write([]byte{0, 0, 0, 1}) - ui := mac.Sum(nil) - hi := make([]byte, len(ui)) - copy(hi, ui) - for i := 1; i < iterCount; i++ { - mac.Reset() - mac.Write(ui) - mac.Sum(ui[:0]) - for j, b := range ui { - hi[j] ^= b - } - } - c.saltedPass = hi -} - -func (c *Client) clientProof() []byte { - mac := hmac.New(c.newHash, c.saltedPass) - mac.Write([]byte("Client Key")) - clientKey := mac.Sum(nil) - hash := c.newHash() - hash.Write(clientKey) - storedKey := hash.Sum(nil) - mac = hmac.New(c.newHash, storedKey) - mac.Write(c.authMsg.Bytes()) - clientProof := mac.Sum(nil) - for i, b := range clientKey { - clientProof[i] ^= b - } - clientProof64 := make([]byte, b64.EncodedLen(len(clientProof))) - b64.Encode(clientProof64, clientProof) - return clientProof64 -} - -func (c *Client) serverSignature() []byte { - mac := hmac.New(c.newHash, c.saltedPass) - mac.Write([]byte("Server Key")) - serverKey := mac.Sum(nil) - - mac = hmac.New(c.newHash, serverKey) - mac.Write(c.authMsg.Bytes()) - serverSignature := mac.Sum(nil) - - encoded := make([]byte, b64.EncodedLen(len(serverSignature))) - b64.Encode(encoded, serverSignature) - return encoded -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl.go deleted file mode 100644 index e5eb92895..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl.go +++ /dev/null @@ -1,193 +0,0 @@ -package pq - -import ( - "crypto/tls" - "crypto/x509" - "io/ioutil" - "net" - "os" - "os/user" - "path/filepath" -) - -// ssl generates a function to upgrade a net.Conn based on the "sslmode" and -// related settings. The function is nil when no upgrade should take place. -func ssl(o values) (func(net.Conn) (net.Conn, error), error) { - verifyCaOnly := false - tlsConf := tls.Config{} - switch mode := o["sslmode"]; mode { - // "require" is the default. - case "", "require": - // We must skip TLS's own verification since it requires full - // verification since Go 1.3. - tlsConf.InsecureSkipVerify = true - - // From http://www.postgresql.org/docs/current/static/libpq-ssl.html: - // - // Note: For backwards compatibility with earlier versions of - // PostgreSQL, if a root CA file exists, the behavior of - // sslmode=require will be the same as that of verify-ca, meaning the - // server certificate is validated against the CA. Relying on this - // behavior is discouraged, and applications that need certificate - // validation should always use verify-ca or verify-full. - if sslrootcert, ok := o["sslrootcert"]; ok { - if _, err := os.Stat(sslrootcert); err == nil { - verifyCaOnly = true - } else { - delete(o, "sslrootcert") - } - } - case "verify-ca": - // We must skip TLS's own verification since it requires full - // verification since Go 1.3. - tlsConf.InsecureSkipVerify = true - verifyCaOnly = true - case "verify-full": - tlsConf.ServerName = o["host"] - case "disable": - return nil, nil - default: - return nil, fmterrorf(`unsupported sslmode %q; only "require" (default), "verify-full", "verify-ca", and "disable" supported`, mode) - } - - err := sslClientCertificates(&tlsConf, o) - if err != nil { - return nil, err - } - err = sslCertificateAuthority(&tlsConf, o) - if err != nil { - return nil, err - } - - // Accept renegotiation requests initiated by the backend. - // - // Renegotiation was deprecated then removed from PostgreSQL 9.5, but - // the default configuration of older versions has it enabled. Redshift - // also initiates renegotiations and cannot be reconfigured. - tlsConf.Renegotiation = tls.RenegotiateFreelyAsClient - - return func(conn net.Conn) (net.Conn, error) { - client := tls.Client(conn, &tlsConf) - if verifyCaOnly { - err := sslVerifyCertificateAuthority(client, &tlsConf) - if err != nil { - return nil, err - } - } - return client, nil - }, nil -} - -// sslClientCertificates adds the certificate specified in the "sslcert" and -// "sslkey" settings, or if they aren't set, from the .postgresql directory -// in the user's home directory. The configured files must exist and have -// the correct permissions. -func sslClientCertificates(tlsConf *tls.Config, o values) error { - sslinline := o["sslinline"] - if sslinline == "true" { - cert, err := tls.X509KeyPair([]byte(o["sslcert"]), []byte(o["sslkey"])) - if err != nil { - return err - } - tlsConf.Certificates = []tls.Certificate{cert} - return nil - } - - // user.Current() might fail when cross-compiling. We have to ignore the - // error and continue without home directory defaults, since we wouldn't - // know from where to load them. - user, _ := user.Current() - - // In libpq, the client certificate is only loaded if the setting is not blank. - // - // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1036-L1037 - sslcert := o["sslcert"] - if len(sslcert) == 0 && user != nil { - sslcert = filepath.Join(user.HomeDir, ".postgresql", "postgresql.crt") - } - // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1045 - if len(sslcert) == 0 { - return nil - } - // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1050:L1054 - if _, err := os.Stat(sslcert); os.IsNotExist(err) { - return nil - } else if err != nil { - return err - } - - // In libpq, the ssl key is only loaded if the setting is not blank. - // - // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L1123-L1222 - sslkey := o["sslkey"] - if len(sslkey) == 0 && user != nil { - sslkey = filepath.Join(user.HomeDir, ".postgresql", "postgresql.key") - } - - if len(sslkey) > 0 { - if err := sslKeyPermissions(sslkey); err != nil { - return err - } - } - - cert, err := tls.LoadX509KeyPair(sslcert, sslkey) - if err != nil { - return err - } - - tlsConf.Certificates = []tls.Certificate{cert} - return nil -} - -// sslCertificateAuthority adds the RootCA specified in the "sslrootcert" setting. -func sslCertificateAuthority(tlsConf *tls.Config, o values) error { - // In libpq, the root certificate is only loaded if the setting is not blank. - // - // https://github.com/postgres/postgres/blob/REL9_6_2/src/interfaces/libpq/fe-secure-openssl.c#L950-L951 - if sslrootcert := o["sslrootcert"]; len(sslrootcert) > 0 { - tlsConf.RootCAs = x509.NewCertPool() - - sslinline := o["sslinline"] - - var cert []byte - if sslinline == "true" { - cert = []byte(sslrootcert) - } else { - var err error - cert, err = ioutil.ReadFile(sslrootcert) - if err != nil { - return err - } - } - - if !tlsConf.RootCAs.AppendCertsFromPEM(cert) { - return fmterrorf("couldn't parse pem in sslrootcert") - } - } - - return nil -} - -// sslVerifyCertificateAuthority carries out a TLS handshake to the server and -// verifies the presented certificate against the CA, i.e. the one specified in -// sslrootcert or the system CA if sslrootcert was not specified. -func sslVerifyCertificateAuthority(client *tls.Conn, tlsConf *tls.Config) error { - err := client.Handshake() - if err != nil { - return err - } - certs := client.ConnectionState().PeerCertificates - opts := x509.VerifyOptions{ - DNSName: client.ConnectionState().ServerName, - Intermediates: x509.NewCertPool(), - Roots: tlsConf.RootCAs, - } - for i, cert := range certs { - if i == 0 { - continue - } - opts.Intermediates.AddCert(cert) - } - _, err = certs[0].Verify(opts) - return err -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl_permissions.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl_permissions.go deleted file mode 100644 index 014af6a16..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl_permissions.go +++ /dev/null @@ -1,21 +0,0 @@ -//go:build !windows -// +build !windows - -package pq - -import "os" - -// sslKeyPermissions checks the permissions on user-supplied ssl key files. -// The key file should have very little access. -// -// libpq does not check key file permissions on Windows. -func sslKeyPermissions(sslkey string) error { - info, err := os.Stat(sslkey) - if err != nil { - return err - } - if info.Mode().Perm()&0077 != 0 { - return ErrSSLKeyHasWorldPermissions - } - return nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl_test.go deleted file mode 100644 index e00522e76..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl_test.go +++ /dev/null @@ -1,282 +0,0 @@ -package pq - -// This file contains SSL tests - -import ( - _ "crypto/sha256" - "crypto/x509" - "database/sql" - "os" - "path/filepath" - "testing" -) - -func maybeSkipSSLTests(t *testing.T) { - // Require some special variables for testing certificates - if os.Getenv("PQSSLCERTTEST_PATH") == "" { - t.Skip("PQSSLCERTTEST_PATH not set, skipping SSL tests") - } - - value := os.Getenv("PQGOSSLTESTS") - if value == "" || value == "0" { - t.Skip("PQGOSSLTESTS not enabled, skipping SSL tests") - } else if value != "1" { - t.Fatalf("unexpected value %q for PQGOSSLTESTS", value) - } -} - -func openSSLConn(t *testing.T, conninfo string) (*sql.DB, error) { - db, err := openTestConnConninfo(conninfo) - if err != nil { - // should never fail - t.Fatal(err) - } - // Do something with the connection to see whether it's working or not. - tx, err := db.Begin() - if err == nil { - return db, tx.Rollback() - } - _ = db.Close() - return nil, err -} - -func checkSSLSetup(t *testing.T, conninfo string) { - _, err := openSSLConn(t, conninfo) - if pge, ok := err.(*Error); ok { - if pge.Code.Name() != "invalid_authorization_specification" { - t.Fatalf("unexpected error code '%s'", pge.Code.Name()) - } - } else { - t.Fatalf("expected %T, got %v", (*Error)(nil), err) - } -} - -// Connect over SSL and run a simple query to test the basics -func TestSSLConnection(t *testing.T) { - maybeSkipSSLTests(t) - // Environment sanity check: should fail without SSL - checkSSLSetup(t, "sslmode=disable user=pqgossltest") - - db, err := openSSLConn(t, "sslmode=require user=pqgossltest") - if err != nil { - t.Fatal(err) - } - rows, err := db.Query("SELECT 1") - if err != nil { - t.Fatal(err) - } - rows.Close() -} - -// Test sslmode=verify-full -func TestSSLVerifyFull(t *testing.T) { - maybeSkipSSLTests(t) - // Environment sanity check: should fail without SSL - checkSSLSetup(t, "sslmode=disable user=pqgossltest") - - // Not OK according to the system CA - _, err := openSSLConn(t, "host=postgres sslmode=verify-full user=pqgossltest") - if err == nil { - t.Fatal("expected error") - } - _, ok := err.(x509.UnknownAuthorityError) - if !ok { - _, ok := err.(x509.HostnameError) - if !ok { - t.Fatalf("expected x509.UnknownAuthorityError or x509.HostnameError, got %#+v", err) - } - } - - rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt") - rootCert := "sslrootcert=" + rootCertPath + " " - // No match on Common Name - _, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=verify-full user=pqgossltest") - if err == nil { - t.Fatal("expected error") - } - _, ok = err.(x509.HostnameError) - if !ok { - t.Fatalf("expected x509.HostnameError, got %#+v", err) - } - // OK - _, err = openSSLConn(t, rootCert+"host=postgres sslmode=verify-full user=pqgossltest") - if err != nil { - t.Fatal(err) - } -} - -// Test sslmode=require sslrootcert=rootCertPath -func TestSSLRequireWithRootCert(t *testing.T) { - maybeSkipSSLTests(t) - // Environment sanity check: should fail without SSL - checkSSLSetup(t, "sslmode=disable user=pqgossltest") - - bogusRootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "bogus_root.crt") - bogusRootCert := "sslrootcert=" + bogusRootCertPath + " " - - // Not OK according to the bogus CA - _, err := openSSLConn(t, bogusRootCert+"host=postgres sslmode=require user=pqgossltest") - if err == nil { - t.Fatal("expected error") - } - _, ok := err.(x509.UnknownAuthorityError) - if !ok { - t.Fatalf("expected x509.UnknownAuthorityError, got %s, %#+v", err, err) - } - - nonExistentCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "non_existent.crt") - nonExistentCert := "sslrootcert=" + nonExistentCertPath + " " - - // No match on Common Name, but that's OK because we're not validating anything. - _, err = openSSLConn(t, nonExistentCert+"host=127.0.0.1 sslmode=require user=pqgossltest") - if err != nil { - t.Fatal(err) - } - - rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt") - rootCert := "sslrootcert=" + rootCertPath + " " - - // No match on Common Name, but that's OK because we're not validating the CN. - _, err = openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=require user=pqgossltest") - if err != nil { - t.Fatal(err) - } - // Everything OK - _, err = openSSLConn(t, rootCert+"host=postgres sslmode=require user=pqgossltest") - if err != nil { - t.Fatal(err) - } -} - -// Test sslmode=verify-ca -func TestSSLVerifyCA(t *testing.T) { - maybeSkipSSLTests(t) - // Environment sanity check: should fail without SSL - checkSSLSetup(t, "sslmode=disable user=pqgossltest") - - // Not OK according to the system CA - { - _, err := openSSLConn(t, "host=postgres sslmode=verify-ca user=pqgossltest") - if _, ok := err.(x509.UnknownAuthorityError); !ok { - t.Fatalf("expected %T, got %#+v", x509.UnknownAuthorityError{}, err) - } - } - - // Still not OK according to the system CA; empty sslrootcert is treated as unspecified. - { - _, err := openSSLConn(t, "host=postgres sslmode=verify-ca user=pqgossltest sslrootcert=''") - if _, ok := err.(x509.UnknownAuthorityError); !ok { - t.Fatalf("expected %T, got %#+v", x509.UnknownAuthorityError{}, err) - } - } - - rootCertPath := filepath.Join(os.Getenv("PQSSLCERTTEST_PATH"), "root.crt") - rootCert := "sslrootcert=" + rootCertPath + " " - // No match on Common Name, but that's OK - if _, err := openSSLConn(t, rootCert+"host=127.0.0.1 sslmode=verify-ca user=pqgossltest"); err != nil { - t.Fatal(err) - } - // Everything OK - if _, err := openSSLConn(t, rootCert+"host=postgres sslmode=verify-ca user=pqgossltest"); err != nil { - t.Fatal(err) - } -} - -// Authenticate over SSL using client certificates -func TestSSLClientCertificates(t *testing.T) { - maybeSkipSSLTests(t) - // Environment sanity check: should fail without SSL - checkSSLSetup(t, "sslmode=disable user=pqgossltest") - - const baseinfo = "sslmode=require user=pqgosslcert" - - // Certificate not specified, should fail - { - _, err := openSSLConn(t, baseinfo) - if pge, ok := err.(*Error); ok { - if pge.Code.Name() != "invalid_authorization_specification" { - t.Fatalf("unexpected error code '%s'", pge.Code.Name()) - } - } else { - t.Fatalf("expected %T, got %v", (*Error)(nil), err) - } - } - - // Empty certificate specified, should fail - { - _, err := openSSLConn(t, baseinfo+" sslcert=''") - if pge, ok := err.(*Error); ok { - if pge.Code.Name() != "invalid_authorization_specification" { - t.Fatalf("unexpected error code '%s'", pge.Code.Name()) - } - } else { - t.Fatalf("expected %T, got %v", (*Error)(nil), err) - } - } - - // Non-existent certificate specified, should fail - { - _, err := openSSLConn(t, baseinfo+" sslcert=/tmp/filedoesnotexist") - if pge, ok := err.(*Error); ok { - if pge.Code.Name() != "invalid_authorization_specification" { - t.Fatalf("unexpected error code '%s'", pge.Code.Name()) - } - } else { - t.Fatalf("expected %T, got %v", (*Error)(nil), err) - } - } - - certpath, ok := os.LookupEnv("PQSSLCERTTEST_PATH") - if !ok { - t.Fatalf("PQSSLCERTTEST_PATH not present in environment") - } - - sslcert := filepath.Join(certpath, "postgresql.crt") - - // Cert present, key not specified, should fail - { - _, err := openSSLConn(t, baseinfo+" sslcert="+sslcert) - if _, ok := err.(*os.PathError); !ok { - t.Fatalf("expected %T, got %#+v", (*os.PathError)(nil), err) - } - } - - // Cert present, empty key specified, should fail - { - _, err := openSSLConn(t, baseinfo+" sslcert="+sslcert+" sslkey=''") - if _, ok := err.(*os.PathError); !ok { - t.Fatalf("expected %T, got %#+v", (*os.PathError)(nil), err) - } - } - - // Cert present, non-existent key, should fail - { - _, err := openSSLConn(t, baseinfo+" sslcert="+sslcert+" sslkey=/tmp/filedoesnotexist") - if _, ok := err.(*os.PathError); !ok { - t.Fatalf("expected %T, got %#+v", (*os.PathError)(nil), err) - } - } - - // Key has wrong permissions (passing the cert as the key), should fail - if _, err := openSSLConn(t, baseinfo+" sslcert="+sslcert+" sslkey="+sslcert); err != ErrSSLKeyHasWorldPermissions { - t.Fatalf("expected %s, got %#+v", ErrSSLKeyHasWorldPermissions, err) - } - - sslkey := filepath.Join(certpath, "postgresql.key") - - // Should work - if db, err := openSSLConn(t, baseinfo+" sslcert="+sslcert+" sslkey="+sslkey); err != nil { - t.Fatal(err) - } else { - rows, err := db.Query("SELECT 1") - if err != nil { - t.Fatal(err) - } - if err := rows.Close(); err != nil { - t.Fatal(err) - } - if err := db.Close(); err != nil { - t.Fatal(err) - } - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl_windows.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl_windows.go deleted file mode 100644 index 73663c8f1..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/ssl_windows.go +++ /dev/null @@ -1,10 +0,0 @@ -//go:build windows -// +build windows - -package pq - -// sslKeyPermissions checks the permissions on user-supplied ssl key files. -// The key file should have very little access. -// -// libpq does not check key file permissions on Windows. -func sslKeyPermissions(string) error { return nil } diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/url.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/url.go deleted file mode 100644 index aec6e95be..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/url.go +++ /dev/null @@ -1,76 +0,0 @@ -package pq - -import ( - "fmt" - "net" - nurl "net/url" - "sort" - "strings" -) - -// ParseURL no longer needs to be used by clients of this library since supplying a URL as a -// connection string to sql.Open() is now supported: -// -// sql.Open("postgres", "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full") -// -// It remains exported here for backwards-compatibility. -// -// ParseURL converts a url to a connection string for driver.Open. -// Example: -// -// "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full" -// -// converts to: -// -// "user=bob password=secret host=1.2.3.4 port=5432 dbname=mydb sslmode=verify-full" -// -// A minimal example: -// -// "postgres://" -// -// This will be blank, causing driver.Open to use all of the defaults -func ParseURL(url string) (string, error) { - u, err := nurl.Parse(url) - if err != nil { - return "", err - } - - if u.Scheme != "postgres" && u.Scheme != "postgresql" { - return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme) - } - - var kvs []string - escaper := strings.NewReplacer(`'`, `\'`, `\`, `\\`) - accrue := func(k, v string) { - if v != "" { - kvs = append(kvs, k+"='"+escaper.Replace(v)+"'") - } - } - - if u.User != nil { - v := u.User.Username() - accrue("user", v) - - v, _ = u.User.Password() - accrue("password", v) - } - - if host, port, err := net.SplitHostPort(u.Host); err != nil { - accrue("host", u.Host) - } else { - accrue("host", host) - accrue("port", port) - } - - if u.Path != "" { - accrue("dbname", u.Path[1:]) - } - - q := u.Query() - for k := range q { - accrue(k, q.Get(k)) - } - - sort.Strings(kvs) // Makes testing easier (not a performance concern) - return strings.Join(kvs, " "), nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/url_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/url_test.go deleted file mode 100644 index 9b6345595..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/url_test.go +++ /dev/null @@ -1,66 +0,0 @@ -package pq - -import ( - "testing" -) - -func TestSimpleParseURL(t *testing.T) { - expected := "host='hostname.remote'" - str, err := ParseURL("postgres://hostname.remote") - if err != nil { - t.Fatal(err) - } - - if str != expected { - t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected) - } -} - -func TestIPv6LoopbackParseURL(t *testing.T) { - expected := "host='::1' port='1234'" - str, err := ParseURL("postgres://[::1]:1234") - if err != nil { - t.Fatal(err) - } - - if str != expected { - t.Fatalf("unexpected result from ParseURL:\n+ %v\n- %v", str, expected) - } -} - -func TestFullParseURL(t *testing.T) { - expected := `dbname='database' host='hostname.remote' password='top secret' port='1234' user='username'` - str, err := ParseURL("postgres://username:top%20secret@hostname.remote:1234/database") - if err != nil { - t.Fatal(err) - } - - if str != expected { - t.Fatalf("unexpected result from ParseURL:\n+ %s\n- %s", str, expected) - } -} - -func TestInvalidProtocolParseURL(t *testing.T) { - _, err := ParseURL("http://hostname.remote") - switch err { - case nil: - t.Fatal("Expected an error from parsing invalid protocol") - default: - msg := "invalid connection protocol: http" - if err.Error() != msg { - t.Fatalf("Unexpected error message:\n+ %s\n- %s", - err.Error(), msg) - } - } -} - -func TestMinimalURL(t *testing.T) { - cs, err := ParseURL("postgres://") - if err != nil { - t.Fatal(err) - } - - if cs != "" { - t.Fatalf("expected blank connection string, got: %q", cs) - } -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/user_other.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/user_other.go deleted file mode 100644 index 3dae8f557..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/user_other.go +++ /dev/null @@ -1,10 +0,0 @@ -// Package pq is a pure Go Postgres driver for the database/sql package. - -//go:build js || android || hurd || zos -// +build js android hurd zos - -package pq - -func userCurrent() (string, error) { - return "", ErrCouldNotDetectUsername -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/user_posix.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/user_posix.go deleted file mode 100644 index 5f2d439bc..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/user_posix.go +++ /dev/null @@ -1,25 +0,0 @@ -// Package pq is a pure Go Postgres driver for the database/sql package. - -//go:build aix || darwin || dragonfly || freebsd || (linux && !android) || nacl || netbsd || openbsd || plan9 || solaris || rumprun || illumos -// +build aix darwin dragonfly freebsd linux,!android nacl netbsd openbsd plan9 solaris rumprun illumos - -package pq - -import ( - "os" - "os/user" -) - -func userCurrent() (string, error) { - u, err := user.Current() - if err == nil { - return u.Username, nil - } - - name := os.Getenv("USER") - if name != "" { - return name, nil - } - - return "", ErrCouldNotDetectUsername -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/user_windows.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/user_windows.go deleted file mode 100644 index 2b691267b..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/user_windows.go +++ /dev/null @@ -1,27 +0,0 @@ -// Package pq is a pure Go Postgres driver for the database/sql package. -package pq - -import ( - "path/filepath" - "syscall" -) - -// Perform Windows user name lookup identically to libpq. -// -// The PostgreSQL code makes use of the legacy Win32 function -// GetUserName, and that function has not been imported into stock Go. -// GetUserNameEx is available though, the difference being that a -// wider range of names are available. To get the output to be the -// same as GetUserName, only the base (or last) component of the -// result is returned. -func userCurrent() (string, error) { - pw_name := make([]uint16, 128) - pwname_size := uint32(len(pw_name)) - 1 - err := syscall.GetUserNameEx(syscall.NameSamCompatible, &pw_name[0], &pwname_size) - if err != nil { - return "", ErrCouldNotDetectUsername - } - s := syscall.UTF16ToString(pw_name) - u := filepath.Base(s) - return u, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/uuid.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/uuid.go deleted file mode 100644 index 9a1b9e074..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/uuid.go +++ /dev/null @@ -1,23 +0,0 @@ -package pq - -import ( - "encoding/hex" - "fmt" -) - -// decodeUUIDBinary interprets the binary format of a uuid, returning it in text format. -func decodeUUIDBinary(src []byte) ([]byte, error) { - if len(src) != 16 { - return nil, fmt.Errorf("pq: unable to decode uuid; bad length: %d", len(src)) - } - - dst := make([]byte, 36) - dst[8], dst[13], dst[18], dst[23] = '-', '-', '-', '-' - hex.Encode(dst[0:], src[0:4]) - hex.Encode(dst[9:], src[4:6]) - hex.Encode(dst[14:], src[6:8]) - hex.Encode(dst[19:], src[8:10]) - hex.Encode(dst[24:], src[10:16]) - - return dst, nil -} diff --git a/src/test/regress/go_driver_test/src/github.com/lib/pq/uuid_test.go b/src/test/regress/go_driver_test/src/github.com/lib/pq/uuid_test.go deleted file mode 100644 index 8ecee2fde..000000000 --- a/src/test/regress/go_driver_test/src/github.com/lib/pq/uuid_test.go +++ /dev/null @@ -1,46 +0,0 @@ -package pq - -import ( - "reflect" - "strings" - "testing" -) - -func TestDecodeUUIDBinaryError(t *testing.T) { - t.Parallel() - _, err := decodeUUIDBinary([]byte{0x12, 0x34}) - - if err == nil { - t.Fatal("Expected error, got none") - } - if !strings.HasPrefix(err.Error(), "pq:") { - t.Errorf("Expected error to start with %q, got %q", "pq:", err.Error()) - } - if !strings.Contains(err.Error(), "bad length: 2") { - t.Errorf("Expected error to contain length, got %q", err.Error()) - } -} - -func BenchmarkDecodeUUIDBinary(b *testing.B) { - x := []byte{0x03, 0xa3, 0x52, 0x2f, 0x89, 0x28, 0x49, 0x87, 0x84, 0xd6, 0x93, 0x7b, 0x36, 0xec, 0x27, 0x6f} - - for i := 0; i < b.N; i++ { - decodeUUIDBinary(x) - } -} - -func TestDecodeUUIDBackend(t *testing.T) { - db := openTestConn(t) - defer db.Close() - - var s = "a0ecc91d-a13f-4fe4-9fce-7e09777cc70a" - var scanned interface{} - - err := db.QueryRow(`SELECT $1::uuid`, s).Scan(&scanned) - if err != nil { - t.Fatalf("Expected no error, got %v", err) - } - if !reflect.DeepEqual(scanned, []byte(s)) { - t.Errorf("Expected []byte(%q), got %T(%q)", s, scanned, scanned) - } -}